« 新サービスclippの紹介(あらためて) | メイン | 見ないと損する ソフトウェアテスト関連サイト色々 »

シェル(bash)スクリプトを書くときのTips
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

尾藤正人(a.k.a BTO)です

UNIXを使う時にはシェルスクリプトをよく使います。
ちょっとしたコマンドを実行するには、シェルスクリプトは非常に便利です。
今回はシェルスクリプトを書くときに覚えておいた方が便利なTipsを紹介します。

非互換性

ここで紹介するものは基本的にbashで動作するものになります。
伝統的なBourne Shellでは動作しないことが多くあると思います。
しかしながら最近はbashがメインで使われることが多いので、"だいだいの環境で動くからおk"ぐらいのノリで使ってもらえればと思います。

$(...)

コマンドを"$(", ")"で囲むと実行結果をコマンドラインに代入してくれます。
一見これは"`"(バッククオート)と同じに見えますが、"$()"にはネストができるという利点があります。

例えばシェルスクリプト自身の絶対パスを取得するのは次のようにできます。

echo $(cd $(dirname $0);pwd)

バッククオートだと一時変数に代入しないとできませんが、"$()"を使うとネストが可能なので、一発で取得する事ができます。
ちなみにこれは、相対パスでも絶対パスでもうまく動作します。

((...)), $((...))

元々シェルは数値演算能力を持たないので、シェルスクリプト内で数値演算を行うには"expr"という外部コマンドを呼び出していました。
最近のシェルだと"((", "))"で囲むことで数値演算を行ってくれるようになってます。
"((...))"を評価した結果がそれぞれ、"0", "0以外"で終了ステータスが "1", "0"になります(ややこしや〜)。
演算結果をコマンドラインに代入したい場合は"$((", "))"で囲めばできます。

"$((...))", "((...))"を使うメリットはいくつかあります。

  • 内部コマンドなので処理が速い
  • 演算子の間にスペースをあける必要がない
  • 浮動小数点が扱える(bashでは使えなくて、zshの話でした。ご指摘ありがとうございます)
if ((1)); then    # ((1))は終了ステータスが"0"なので"true"が表示される
  echo true
else
  echo false
fi
$ echo $((1+2))    # 演算子の間にスペースがいらない
3
$ echo $(expr 1+2)   # exprだと演算子の間にスペースが必要
1+2
$ echo $(expr 1 + 2)    # スペースあけるとうまくいく
3
$ echo $((1.1+2.2))    # 浮動小数点もいける
3.3000000000000003
$ echo $(expr 1.1 + 2.2)    # exprだと浮動小数点はダメ
expr: non-numeric argument

read(Borne Shellでも使える?)

findの出力結果をベースに大量のファイルに一気に処理を行う時はどうやるでしょうか。
よくみかけるのが、こんなスクリプトです。

for f in $(find ...); do
  echo $f
  echo $(basename $f)
done

これは"find"の実行結果が長くない時には、うまく動作します。
"find"の実行結果が長いときによく利用するのが"xargs"です。

find ... | xargs command

xargsは僕も大好きなコマンドの1つで、1つのコマンドを複数ファイルに実行するのにとても便利です。
ただ複数のコマンドを実行したい時に不便です。

これは read という内部コマンドを使うとうまく動作します。
read は標準入力から読み込んだデータを引数に指定した変数に代入します。
"find"の出力結果をパイプで流して、"read"を使って順番に変数に代入すると、"find"の実行結果が長くても動作しますし、複数のコマンドの実行も簡単に行えます。

find ... | while read f; do
  echo $f
  echo $(basename $f)
done

まとめ

シェルスクリプトを書く時に覚えておくと便利なTipsを紹介してみました。
他にもいろいろ便利な書き方があるかと思います。
シェルスクリプトは使いこなせるようになると非常に便利です。
みなさんもいろいろ勉強してみてはいかがでしょうか。

トラックバック

このエントリーのトラックバックURL:
http://www.unoh.net/mt32/mt-tb.cgi/1486

コメント

echo `cd \`dirname $0\`; pwd`

なるほどー
確かにエスケープしてやればできますね

ついでに…

find ... -exec /bin/sh -c 'echo {}; echo `basename {}`' \;

とか

find ... -print -exec basename \{\} \;

とか

find ... -exec echo \{\} \; -exec basename \{\} \;

とかでも

できるのは分かってますし、できないとも書いてないですが、不便ではないかと(もともとの主旨)

コメントを投稿


画像の中に見える文字を入力してください。

  [PR] 転職
ウノウラボはウノウ株式会社のエンジニア/デザイナーによる大小のアウトプットを行っていく場です。

現在ウノウは絶賛人材募集中です。詳細は求人ページへ。

About

2008年9月 2日 11:47に投稿されたエントリーのページです。

ひとつ前の投稿は「新サービスclippの紹介(あらためて)」です。

次の投稿は「見ないと損する ソフトウェアテスト関連サイト色々」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

ウノウサービス