シェルスクリプトIF文、数値・文字列比較、ファイル・ディレクトリ存在判定

シェルスクリプトのif文。数値や文字列、ファイル/ディレクトリの判定などいろいろできますが、オプションがややこしく。
ということで、メモ。

数値・文字列の判定

数値・文字列の共通演算子
演算子説明
-eq, =一致の場合、真
-ne, !=不一致の場合、真
-gt
-ge>=
-lt
-le<=

文字列の長さ判定
演算子説明
-z文字列長がゼロ場合、真
-n文字列長がゼロより大きい場合、真

数値、文字列とも不等号記号(<、>)は使えない。>を使った場合、リダイレクトとして作用する。否定は、演算子の前に!(! -eq)。

また、文字列が未定義の場合はexpression expectedやoperator expectedなどのエラーがでる。この場合はダブルクォートで囲む必要がある。より古い書き方として、"X$STR" = "X" のようにされる場合もある。実行例は下記に。
if.sh
  1:
  2:
  3:
  4:
  5:
  6:
  7:
  8:
  9:
 10:
 11:
#!/bin/sh

STR=
TEST="str test1"
if [ $STR = "" ]; then
    echo "$TEST: true"
fi
TEST="str test2"
if [ "$STR" = "" ]; then
    echo "$TEST: true"
fi
実行結果
$ ./if.sh
./if.sh: line 5: [: =: unary operator expected
str test2: true


ファイル・ディレクトリの判定

演算子説明
-f対象がファイルの場合、真
-d対象がディレクトリの場合、真
-e対象が存在する場合、真
-r対象にread権限がある場合、真
-w対象にwrite権限がある場合、真
-x対象に実行権限がある場合、真
-f、-d 以外はファイル・ディレクトリに利用可能。否定は、演算子の前に!(! -f)。
実行例は下記
  1:
  2:
  3:
  4:
  5:
  6:
  7:
  8:
  9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
#!/bin/sh

if [ -f file1.txt ]; then
    echo "file1.txt is file"
fi
if [ ! -f file1.txt ]; then
    echo "file1.txt is NOT file"
fi
if [ -d file1.txt ]; then
    echo "file1.txt is dir"
fi
if [ -d dir1 ]; then
    echo "dir1 is dir"
fi
if [ -e file1.txt ]; then
    echo "file1.txt exist"
fi
if [ -e dir1 ]; then
    echo "dir1 exist"
fi
実行結果
user01@PC01[if_test]$ ll
total 13
drwxr-xr-x+ 1 user01 None    0 Jul 21 21:55 .
drwxr-xr-x+ 1 user01 None    0 Jul 21 20:38 ..
d-wx-wx-wx+ 1 user01 None    0 Jul 21 20:39 dir1
-rw-r--r--  1 user01 None    5 Jul 21 20:38 file1.txt
-rwxr-xr-x  1 user01 None 1447 Jul 21 21:55 if.sh

$ ./if.sh
file1.txt is file
dir1 is dir
file1.txt exist
dir1 exist


久々のネタは、超初歩的ifでご機嫌を伺ってみました。

sedコマンドのスラッシュ(/)エスケープ、変数展開、ファイルの上書きなど

URLのスラッシュのスケープは何気に面倒だったりするのでそのメモ。

test.txt - テスト用入力ファイル
http://www.yahoo.co.jp
ENV=LANG

区切り文字(デリミタ)の変更

s///置換の区切り文字は何でもよくってsに続く1文字で指定可能。!や@なんかもOK
#!/bin/sh

echo "*** separate=!"
sed s!http://www.yahoo.co.jp!http://www.google.com!g test.txt

echo "*** separate=@"
sed s@http://www.yahoo.co.jp@http://www.google.com@g test.txt

実行結果
*** separate=!
http://www.google.com
ENV=LANG

*** separate=@
http://www.google.com
ENV=LANG


変数の展開・エスケープ

'(シングルクオート)で囲むことによって対応可能。
#!/bin/sh

LANG=envlang

echo "*** 変数の展開"
sed s/LANG/$LANG/g test.txt

echo "*** 変数のエスケープ"
sed s/LANG/'$LANG'/g test.txt

実行結果
*** 変数の展開
http://www.google.com
ENV=envlang

*** 変数のエスケープ
http://www.google.com
ENV=$LANG


入力ファイルへの上書き

-iオプションを付けるだけ。
#!/bin/sh

echo "*** separate=@ and 入力ファイルを上書き"
sed -i s@http://www.yahoo.co.jp@http://www.google.com@g test.txt
cat test.txt

実行結果
*** separate=@ and 入力ファイルを上書き
http://www.google.com
ENV=LANG


sedによるファイル内文字列の一括置換

何かと役立つ、sedコマンドによるファイル内文字列の一括置換

サンプルのファイルは下記のとおり、全部で10行で1-5行目までをもう一度繰り返し。
1.txt
  1 11111
  2 12345
  3 ABCDE
  4 abcde
  5 AAAAA
  6 11111
  7 12345
  8 ABCDE
  9 abcde
 10 AAAAA

オプションはいろいろありますが、とりあえずは下記だけ知ってれば何とかなるかも。
script機能
s/src/dst/正規表現の置換。最後にgを付ければ1行内の全マッチの置換を行う。1行だけ処理するのとは違う。
y/abc/ABC/パターンスペースの置換。sとの違いは、一文字ずつ変換を行う。aをAに、bをBというように
X数字を1つのみ指定した場合は、X行目のみ処理する。
from,to数字を2つ指定した場合は、from行目からto行目までを処理する。

また、sedの変換結果はstdoutに出るので、複数ファイルをまとめて置換するとまとめstdoutに出るのでパースが必要。シェルスクリプト等で1ファイルづつループで処理させるなどするといいかも(というかこういうの既にあったりして使いまわしてる。書いてもすぐだけど・・・)。

s/src/dst/の例

user01@PC01[tmp]$ sed -e "s/1/A/g" 1.txt
AAAAA
A2345
ABCDE
abcde
AAAAA
AAAAA
A2345
ABCDE
abcde
AAAAA

user01@PC01[tmp]$ sed -e "s/1/A/" 1.txt
A1111
A2345
ABCDE
abcde
AAAAA
A1111
A2345
ABCDE
abcde
AAAAA

y/src/dst/の例

yはやってみないと良くわからないかも。下記の例だと、1>6、2>7、3>8に1文字ずつ変換。
123を678に変換するのとは違う。
user01@PC01[tmp]$ sed -e "y/123/678/" 1.txt
66666
67845
ABCDE
abcde
AAAAA
66666
67845
ABCDE
abcde
AAAAA

行数指定の例

2行目だけ変換
user01@PC01[tmp]$ sed -e "2 s/1/A/" 1.txt
11111
A2345
ABCDE
abcde
AAAAA
11111
12345
ABCDE
abcde
AAAAA

6,7行目だけ変換
user01@PC01[tmp]$ sed -e "6,7 s/1/Z/g" 1.txt
11111
12345
ABCDE
abcde
AAAAA
ZZZZZ
Z2345
ABCDE
abcde
AAAAA

diffコマンドとpatch(パッチ)の適応

diffコマンドとpatch(パッチ)の適応についてのメモ。

マスターのソースに修正を加える場合、修正後のファイルを送る場合とパッチのみを送る場合があります。逆にもらう場合もあります。で使い方。

diffコマンド

ほとんど下のオプションのみ知っていればOKかと。diffで差分だけを見たいときはオプションなしでもほとんど問題なし。
オプション内容
-cコンテキスト形式(context format)の出力
-uユニファイド形式(unified format)の出力
-rサブディレクトリ以下もリカーシブにdiffを実行

unified形式の例(個人的にはこれが一番見やすくて好きです)
--- org.php     2012-02-26 07:45:02.000000000 -0600
+++ mod.php     2012-02-26 07:45:04.000000000 -0600
@@ -1,8 +1,7 @@
 #!/usr/local/bin/php
 <?php

-$prm_opts = getopt ("a:");
+$prm_opts = getopt ("a:b:");

 print "*** a=". $prm_opts["a"] . "\n";
-
-// EOF
+print "*** b=". $prm_opts["b"] . "\n";

patchコマンド

patchコマンドはオリジナルに直接更新をかけるので、バックアップか出力先を指定して実行した方がよい。
また、修正にパッチファイルだけを渡される場合があるのですがレビューなどをする場合はパッチとパッチ適用後両方のファイルを渡したほうが親切です。
オプション内容
-cパッチファイルがコンテキスト形式の場合指定(なくても可)
-uパッチファイルがユニファイド形式の場合指定(なくても可)
-bバックアップファイルを作成する
-oパッチを適用した新しいファイルを指定されたファイルに出力する

実行例は下記に。

[続きを見る]

dateコマンド(Linux) フォーマット日付、Unixタイムスタンプ、X日前後の取得

dateコマンド(Linux編)
dateコマンドもバージョンによって方言がかなりあり、BSD系とLinux系ではかなりオプションが異なります。
ということで、Linux編。確認したdateコマンドの正確なバージョンは以下のとおり。
$ date --version
date (GNU coreutils) 5.97
Copyright (C) 2006 Free Software Foundation, Inc.

フォーマット日付の取得
$ date  "+%Y%m%d %H:%M:%S"
20111128 09:00:00

Unixタイムスタンプの取得
現在時刻をUnixタイムで取得
$ date "+%s"
1322492450

$ date "+%s" -d "20111128 09:00:00"
1322492400

Unixタイムスタンプからフォーマット日付への変換
20111128 09:00:00(1322492400) から 1分後を取得
$ date  "+%Y%m%d %H:%M:%S" -d "1970-01-01 GMT +1322492460 second"
20111128 09:01:00

1日前1日後など、X日前後の取得。今日が20111128として。
1日前
$ date  "+%Y%m%d %H:%M:%S" -d '1 days ago'
20111127 09:00:00

10ヵ月後
$ date  "+%Y%m%d %H:%M:%S" -d '10 month'
20120928 09:00:00
X日前等、基準日より過去の日付を取得する場合は、'X days ago' (agoを付記)、
X日後等、基準日より未来の日付を取得する場合は、'X day'

カテゴリ

Amazon

アクセスランキング

[ジャンルランキング]
コンピュータ
249位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
38位
アクセスランキングを見る>>

RSSリンクの表示

ブロとも申請フォーム

Copyright © nopgm