ここ数年、再利用するかも知れないコードは可読性がいいPythonで書くことが多かったものの、最近
そこで改めてbashのマニュアル等を確認したら、
bashの来歴
Linux系ディストリビューションのデフォルトのシェルであるbashは、GNUプロジェクトが開発したシェルで、"Bourne Again SH"の略になっています。
この"Bourne Again"というのは、"Born Again
UNIXの世界では、
最初のシェルは、UNIXの生みの親であるケン・
一方このころ、UNIXの可能性に興味を持ったカリフォルニア大学バークレー校のCSRG
1980年代になると、自由にコピーや改造ができる
bashの最初のバージョンが公開されたのが1989年、その後も開発は続き、現在の最新版は5.
bashの便利機能
さて、前置きがずいぶん長くなりましたが、今回は筆者が最近便利に感じているbashの機能のうち、コマンドラインの反復展開や変数の置換、削除回りを紹介しましょう。
{ } による反復展開
入力文中の中カッコ
$ echo {a,b}.txt a.txt b.txt
"{…}"内には2つ以上の要素を指定することも可能で、"{…}"が複数あれば組み合わせ総当たり的に展開されます。
$ echo {a,b,c}-{01,02,03}.txt a-01.txt a-02.txt a-03.txt b-01.txt b-02.txt b-03.txt c-01.txt c-02.txt c-03.txt
コンマ前後に要素を指定しないことも可能で、要素を指定しなければ無いものとして展開するので、バックアップ用にファイル名を変更する場合はこういう指定ができます。
$ ls log.dat $ mv -v log.dat{,.old} 名前変更: 'log.dat' -> 'log.dat.old' $ ls log.dat.old
もちろん、"{…}"がパス等の文字列中にあっても大丈夫です。
$ echo /{,old}home/kojima /home/kojima /oldhome/kojima
要素に数字やアルファベットを指定する場合、"〈start〉..〈end〉"の指定で連番と見なされます。
$ echo {1..10}.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt 10.txt $ echo {a..l}.txt a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt
さらに"..〈interval〉"を追加すれば、連番の2つ跳びとか5つ跳びも指定できます。
$ echo {1..10..2}.txt 1.txt 3.txt 5.txt 7.txt 9.txt $ echo {a..z..5}.txt a.txt f.txt k.txt p.txt u.txt z.txt
指定範囲が連番として解釈できない場合は、展開せずにそのまま表示されるようです。
$ echo {a..9}.txt {a..9}.txt
従来、この手の処理には外部の"seq"コマンドを利用したものの、ブレース展開を使えばbashだけで間に合いそうです。
変数の置換、一部削除
画像ファイルをまとめて形式変換したりリネームする際、従来はこんな風に"sed"などを使って新しい名前を生成していました。
$ ls CIMG3424.JPG CIMG3425.JPG CIMG3426.JPG $ for i in *JPG ; do > new=`echo $i | sed "s/JPG/pnm/"` > jpegtopnm $i > $new > done
一方最近のbashでは変数の置換機能があるので、これだけで済みます。
$ for i in *JPG ; do > jpegtopnm $i > ${i/JPG/pnm} > done
2行目の${i/
また、変数の一部を削除するような機能もあります。従来、メールアドレスからログイン名やドメイン名を取り出すには、"cut"や"gawk"を使っていましたが、最近のbashではこう書けます。
$ addr=kojima@linet.gr.jp $ echo $addr kojima@linet.gr.jp $ echo ${addr%@*} kojima $ echo ${addr#*@} linet.gr.jp
前者の${addr%@*}の指定は、変数$addr
もちろん、ワイルドカードを用いず、${addr%.jp}
この後方一致
$ path=/usr/bin/file $ echo ${path##*/} file $ echo ${path%/*} /usr/bin $ echo ${path%%/*}
${path##*/}は前方最長一致で、文字列の最初から"*/"
ちなみに削除する文字列の指定に使えるのはワイルドカード
算術式の評価
bash/
$ a=5 $ b=3 $ echo $a + $b 5 + 3 $ echo "$a + $b" 5 + 3
そのため算術演算したい場合は外部コマンドである"expr"を利用していました。
$ echo `expr $a + $b` 8 $ echo `expr $a * $b ` expr: 構文エラー: 予期しない引数 `file 01.txt.old' $ echo `expr $a \* $b ` 15
なお後者はよくやるミスで、"*
"はそのままだとファイル名選択用のワイルドカードと解釈されてしまうため、乗算演算子として"expr"コマンドに渡すには"\
"でエスケープする必要があります。
一方、最近のbashでは算術展開$(( ))
" 内で直接計算式を記述できます。
$ echo $(($a + $b)) 8 $ echo $(($a * $b)) 15
この機能を使えば"expr"コマンドも必要なくなりそうです。
bshの仕様でシェルスクリプトを学んだ人間にとって中括弧
今回、
しかしながらPlamo Linuxの場合、パッケージのインストール時に使うのはbshと同等の機能しか持たないbusyboxの"ash"なので、ヘタにbashの拡張機能に慣れてしまうとパッケージ作成時に思わぬミスをしでかしそうです。また、この手の凝った表記はしばらく使わないとすぐに忘れてしまうので、半年前に自分で書いたコードを眺めて首をひねっている、将来の自分の姿が目に浮びます
まぁ、このあたりのバランスは難しいものの、せっかく用意されている機能を使わないのも勿体ないので、老犬も少しずつ新しい芸を覚えていくことにしましょう。