!!!シェルスクリプト(bash)メモ 時折使うくせにすぐ忘れる、bashのごく基本的な構文等のメモ。 特にシェルスクリプトとして使用する場合の基礎知識。 !!変数 *参照(load)時は「$」を付ける。代入(store)時は付けない。 **Makefileのように「${変数名}」という参照形式もある。 **代入時に「=」の左右に空白を付けないこと。 ***空白を含む文字列(配列)の代入はクォートすること。 *キーボード入力は「read 変数名」とする。変数名に「$」は付けない。 **よく「echo -n」と併用する。 **パイプで「while read 変数名 ; do 文 ; done」などともする。 **下記のselect構文も参照。 *$0は実行されたコマンド名、$1〜$9は引数。 **shiftで$1を削除して後続を前に詰めることができる。 ***$0には影響なし。 ***perl等のように「変数=shift」とできるわけではない(?)。 !特殊変数 ::$# :::スクリプトへの引数の数。 ::$* :::スクリプトへの全引数。区切り文字を指定できるはずだがその方法を忘れた。 ::$@ :::スクリプトへの全引数。空白区切り。 !defined的なステートメント TODO:そのうち調べて書く、他にも色々あったはず。 *${変数名:=値} *${変数名:-値} *${変数名:+値} *${変数名:?値} !!クォーテーションとエスケープ 元ネタは[akr流(2007-02-26)|https://www.codeblog.org/blog/akr/20070226.html]なのでこちらを見るべき。 bashと言うよりbsh(Bourne Shell)由来のようだが。 エスケープはよくある方法で、「\」の前置で行う。 !シングルクォーテーション *全てがそのままで一切の展開・解釈はない。 *シングルクォーテーション自身を内部でエスケープする方法はない。 どうしても自身を使いたい場合、クォーテーション外に並んでいる文字列はそのまま連結されることを利用し、一度閉じて「\'」とエスケープ表現し連結する。 !ダブルクォーテーション *「\」「$」「`」以外は展開・解釈はない。 **実際には「$」の後の「{}」や「()」は意味を持つ。 **その他の「&」「|」「>」「;」などは特別な意味を失い、その文字自身になる。 *ダブルクォーテーション自身は「\」でエスケープ可能。 !コマンド置換 バッククォート「`」による括りはコマンド置換を表す。 「\」「`」だけでなく「$」をエスケープできるらしいので、展開・解釈の仕様はダブルクォーテーションの場合とほぼ同じのようだ。 $(command)という形式のコマンド置換もある。 こちらは、通常のシェルスクリプトで閉じ括弧が単独で現れる記法はシンタックスエラーになり、これを利用して終了点を検知するようになっているらしく、展開・解釈される記号はない。 !継続行 継続行表記は行終端の「\」で行う。 「\」と続く改行を削除する仕様であり、C言語のように空白に置き換えるわけではない。 !!複数コマンドの実行 !失敗したら・成功したら 「||」で複数のコマンドを区切れば、前のコマンドが失敗した場合に後のコマンドを実行。「&&」で複数のコマンドを区切れば、前のコマンドが成功した場合に後のコマンドを実行。 シェルスクリプト内では「exit」の引数で戻り値を指定できるが、C言語的に0=FALSEと考えるのではなく0=SUCCESSと考える。 つまり0(成功)を返した場合に「&&」の後のコマンドが、0以外(失敗)を返した場合に「||」の後のコマンドが実行される。 !逐次実行とバックグラウンド実行 逐次実行は「;」で区切る。Windowsのコマンドプロンプトのように「&」ではない。 「&」はバックグラウンド実行。 !連結 サブシェルで実行する場合には「()」、現在のシェルの中で実行する場合は「{}」で、 各コマンドは「;」で区切る。改行でもいい。 「()」では単に区切ればよい。「( cd ; mv hoge )」のように。 「{}」では最後に空文が必要。「{ cd ; mv hoge ; }」のように。 !!制御構造 !if {{pre if 条件文; then 文 文 elif 条件文; then 文 文 else 文 文 fi }} {{pre if 条件文 then 文 文 elif 条件文 then 文 文 else 文 文 fi }} {{pre if 条件文; then 文; 文; elif 条件文; then 文; 文; else 文; 文; fi }} !for {{pre for 変数名 in 空白区切りの配列 do 文 文 done }} {{pre for 変数名 in 空白区切りの配列; do 文; 文; done }} break/continueが使用可能で、引数でループ階層数を指定し、多重ループを対象にもできる。 !while/until {{pre while 条件文 do 文 文 done }} {{pre while 条件文; do 文; 文; done }} break/continueが使用可能で、引数でループ階層数を指定し、多重ループを対象にもできる。 !case {{pre case $変数名 in foo) 文 文 ;; *.txt) 文 文 ;; *) 文 文 ;; esac }} {{pre case $変数名 in foo) 文 ;; *.txt|*.text) 文 ;; *) 文 ;; esac }} caseに指定する変数、分岐ラベルはそれぞれクォーテーションも可能。 「*」以外にもbashのワイルドカードが使用可能。 !select {{pre PS3='プロンプト文字列' select 変数名 in 空白区切りの配列 do 文 文 done }} 選択肢を提示し、ユーザに番号で入力させる構文。 ユーザは提示されたメニュー番号で選択するが、スクリプトで変数に格納されるのは選択肢の配列に含まれる文字列になる。 一種のループなので抜け出すにはbreakが必要。不正なメニュー番号は空文字列「""」になるので、無視するようにすれば再度プロンプトが表示される。プロンプト文字列はシェル変数PS3に設定すること。 !!関数化 {{pre 関数名(){ local 変数名=値 文 return 値 } }} *引数は$1〜$9、$@等で使用可能。 *呼び出しに「()」は付けない(?)。 TODO:名前つき引数形式ってなかったっけ?調査。 !!条件文 条件文はifやwhile等の制御構文の条件に指定する。bashの構文のように見えるが、環境によってそれぞれコマンドとして実装されている場合もある(MSYSではbash側で解析しているようだが、MSYSのcoreutilsには.exeとしても用意されている)。このため、条件の指定は一々空白で区切る必要がある。 {{pre if test 条件; then 文 fi }} {{pre if [ 条件 ]; then 文 fi }} !条件 ::文字列 = 文字列 :::2つの文字列が等しい場合に真。 ::文字列 != 文字列 :::2つの文字列が等しくない場合に真。 ::-n 文字列 :::文字列が空でない場合に真。 ::-z 文字列 :::文字列が空の場合に真。 ::-d 文字列 :::文字列が存在するディレクトリの場合に真。 ::-f 文字列 :::文字列が存在するファイルの場合に真。 ::-s 文字列 :::文字列が存在するファイルでサイズが0ではない場合に真。 ::-r 文字列 :::文字列が存在するファイルで読み込み可能の場合に真。 ::-w 文字列 :::文字列が存在するファイルで読み込み可能の場合に真。 ::-eq, -ne, -gt, -ge, -lt, -le :::それぞれ整数としての比較演算子。 ::-a :::後続の条件とのAND。 ::-o :::後続の条件とのOR。 ::! :::後続の条件のNOT。 !!ヒアドキュメント {{pre cat < foo.txt 2>&1」とする。 *「unset」で関数や変数を削除できる。