量子化された無意味な人生

意味深だけど意味が無いブログだよ(:-Q)

bashのちょっと変態っぽい感じの文法メモ

変態そうで変態じゃない、少し変態なbash
最近bashシェルスクリプトをよく書くんですが、結構奇っ怪な文法で便利なのがあるので自分用にメモ。
もうbashちゃんがいないと生きていられないよお…。
csh? zsh? ハッ。ていうこのスタンス。*1

二重かっこで囲って演算子を使う

$(())の中ではbash独自の演算子がつかえる文法。

$ bash << 'EOF'
> a=10
> b=20
> hoge=$((a+b))
> echo $((a/5))
> echo ${hoge}
> EOF
2
30

expr使うよりもbash組み込みのこちらの方が環境依存がなく良いらしい。(参考: bashでexprを使わずにインクリメント処理する。 - 0xDB
exprでは演算子との間にスペース必須だったがこれはスペースがあってもなくてもどちらでも良い。
インクリメントもできるのでだいぶコードがすっきりする。

hoge=`expr $hoge + 1` # exprを使うパターン
hoge=$((hoge++)) # bashの記法を使うパターン

なお、今までの例でわかるとおり二重かっこ中では変数に$マークはつけなくて良い。

Man page of BASHの算術式評価の項目を丸写しだが、以下の演算子を(個人的に)よく使う。

演算子 効果
parameter++, parameter--
++parameter, --parameter
インクリメント、デクリメント。後ろだと評価のあとに演算、前だと演算のあとに評価。
+, - 足し算、引き算
*, /, % かけ算、割り算、剰余(あまり)
** 指数(べき乗)

for文をCとかperlみたいに書く

普通shだとseqなどを使って

for i in `seq 0 100`
   do
   echo "now: $i"
done

みたいな書き方をするが、bashの2重かっこを使うとCとかperlとか俗に言うfor文っぽいforが書ける。

for ((i=0; i<=100; ++i))
   do
   echo "now: $i"
done

seqだけでは対応できないループなども手軽にできるから便利。
二重かっこ内は前述の二重かっこと同様に演算子が使える。
先の項目で書かなかったけど条件判断などに便利そうな演算子は以下のようなものがある。

演算子 効果
<, > より大きい、未満
<=, >= 以下、以上
! 論理否定
&& AND
|| OR
=, *=, /=, %=, +=, -= 代入、演算子付きのものは元の変数に演算して代入

ビット系の演算子は個人的にあまり使わないので割愛した。
もちろん前述の+や**などの演算子も使える。

正規表現を使う

二重丸括弧ではbash独自の式の評価ができたが、testコマンドのような条件式の評価でbash独自の仕様を使うには二重カギ括弧を使う。
bash独自の文法では正規表現を使うことができる。

$ bash << 'EOF'
> a="hogehoge"
> [[ "$a" =~ [0-9] ]] && echo "\"$a\" has num."
> a="123hoge"
> [[ "$a" =~ [0-9] ]] && echo "\"$a\" has num."
> EOF
"123hoge" has num.

なお、正規表現をクオートなどで囲むと正常に動かない。(参考: bashの正規表現マッチングの使い方 - adsaria mood
また、¥dみたいなのは使えない模様*2
testコマンドとbashの二重カギ括弧では終了ステータスが違うとかそういう感じのをどこかで見た気がするが、見つけられなかった…。
追記(2014/05/15): 見つかりました!
if 文と test コマンド - UNIX & Linux コマンド・シェルスクリプト リファレンス
こちらに書いてあるとおり、testコマンドである[は条件内の変数が空になるとエラーを吐いたりしますが、bash組み込みである[[(二重かぎかっこ)ではエラーが出ないようです。

変数に小細工をして使う

参考: bashで変数を簡単に制御するための演算子: 小粋空間
というか上のページがわかりやすいので書く必要ないかも。
一応まとめの表でも作るかー。

記法 効果
${name:-foo} 変数nameが未定義の時デフォルト値fooを使う。
${name:=foo} 変数nameが未定義の時デフォルト値fooを代入する。
${name:+foo} 変数nameに値がセットされているときデフォルト値fooを使う。
${name:?hogehoge} 変数nameが未定義の時"hogehoge"を出力してスクリプトを終了する。

そのほかにもあるみたい。使いどころは限られそうだけど便利そう。

記法 効果
${parameter:offset} 文字列をoffset文字目から使う。offsetは0から始まる。
${parameter:offset:length} 文字列をoffset文字目からlength文字使う。
${!prefix*} または ${!prefix@} prefixから始まる変数名を持つ変数すべてを使う。
${#parameter} 格納された文字数を使う。
${parameter#word}, ${parameter##word} 先頭からの最短一致パターン(#)と最長一致パターン(##)を取り除く。
先頭とマッチしないと取り除かれないので注意。
${parameter%word}, ${parameter%%word} ↑の後方一致パターンバージョン。末尾からマッチさせる。
${parameter/pattern/string} patternにマッチした部分をstringで置換して使う。
/(スラッシュ)が一つだと一度だけ置換、二つだと繰り返し置換される。
削除の場合は最後の/は省略できる。

web上のmanに書いてある大文字小文字変換は自分のmac mountain lion上のbashのmanには無かったし使えなかった。

         ∧_∧   ┌────────────
       ◯( ´∀` )◯ < 僕は、Bashちゃん!
        \    /  └────────────
       _/ __ \_
      (_/   \_)

参考: Man page of BASH

*1:けんか売ってないよ><; 綿矢りさ蹴りたい背中』が結構好きで

*2:情報未確認、もしかしたら書き方が違うだけであるかも