シェルスクリプトIF文、数値・文字列比較、ファイル・ディレクトリ存在判定
- Mon
- 22:03
- シェルスクリプト
シェルスクリプトのif文。数値や文字列、ファイル/ディレクトリの判定などいろいろできますが、オプションがややこしく。
ということで、メモ。
文字列の長さ判定
数値、文字列とも不等号記号(<、>)は使えない。>を使った場合、リダイレクトとして作用する。否定は、演算子の前に!(! -eq)。
また、文字列が未定義の場合はexpression expectedやoperator expectedなどのエラーがでる。この場合はダブルクォートで囲む必要がある。より古い書き方として、"X$STR" = "X" のようにされる場合もある。実行例は下記に。
if.sh
実行結果
-f、-d 以外はファイル・ディレクトリに利用可能。否定は、演算子の前に!(! -f)。
実行例は下記
実行結果
久々のネタは、超初歩的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 | 対象に実行権限がある場合、真 |
実行例は下記
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コマンドのスラッシュ(/)エスケープ、変数展開、ファイルの上書きなど
- Mon
- 00:50
- シェルスクリプト
URLのスラッシュのスケープは何気に面倒だったりするのでそのメモ。
test.txt - テスト用入力ファイル
実行結果
実行結果
実行結果
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によるファイル内文字列の一括置換
- Wed
- 00:16
- シェルスクリプト
何かと役立つ、sedコマンドによるファイル内文字列の一括置換
サンプルのファイルは下記のとおり、全部で10行で1-5行目までをもう一度繰り返し。
1.txt
オプションはいろいろありますが、とりあえずは下記だけ知ってれば何とかなるかも。
また、sedの変換結果はstdoutに出るので、複数ファイルをまとめて置換するとまとめstdoutに出るのでパースが必要。シェルスクリプト等で1ファイルづつループで処理させるなどするといいかも(というかこういうの既にあったりして使いまわしてる。書いてもすぐだけど・・・)。
123を678に変換するのとは違う。
6,7行目だけ変換
サンプルのファイルは下記のとおり、全部で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(パッチ)の適応
- Sun
- 23:15
- シェルスクリプト
diffコマンドとpatch(パッチ)の適応についてのメモ。
マスターのソースに修正を加える場合、修正後のファイルを送る場合とパッチのみを送る場合があります。逆にもらう場合もあります。で使い方。
unified形式の例(個人的にはこれが一番見やすくて好きです)
また、修正にパッチファイルだけを渡される場合があるのですがレビューなどをする場合はパッチとパッチ適用後両方のファイルを渡したほうが親切です。
実行例は下記に。
マスターのソースに修正を加える場合、修正後のファイルを送る場合とパッチのみを送る場合があります。逆にもらう場合もあります。で使い方。
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日前後の取得
- Tue
- 01:09
- シェルスクリプト
dateコマンド(Linux編)
dateコマンドもバージョンによって方言がかなりあり、BSD系とLinux系ではかなりオプションが異なります。
ということで、Linux編。確認したdateコマンドの正確なバージョンは以下のとおり。
フォーマット日付の取得
Unixタイムスタンプの取得
Unixタイムスタンプからフォーマット日付への変換
20111128 09:00:00(1322492400) から 1分後を取得
1日前1日後など、X日前後の取得。今日が20111128として。
X日後等、基準日より未来の日付を取得する場合は、'X day'
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:00X日前等、基準日より過去の日付を取得する場合は、'X days ago' (agoを付記)、
X日後等、基準日より未来の日付を取得する場合は、'X day'