シェルスクリプトノウハウ
昔の記事ですが、IBM DeveloperWorksで紹介されていたUnixコマンドをご紹介。たまに忘れるので備忘録用にまとめておきます。
1コマンドでディレクトリツリー生成
-pオプションを利用
$ mkdir -p tmp/a/b/c
中括弧を使えば複雑なツリーも1コマンドで
$ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}
もし、-pオプションが使えないのならmkdirhierコマンドを
$ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}
展開するディレクトリの指定
$ tar xvf newarc.tar.gz -C tmp/a/b/c
※参考サイトに記述されているコマンドはzshでは動作しなかった
$ tar xvf -C tmp/a/b/c newarc.tar.gz
&&コントロール演算子
1つ目のコマンドが正常終了したとき、2つ目のコマンドを実行(正確にはExitステータスが0のとき)
cd tmp/a/b/c && tar xvf ~/newarc.tar.gz
||コントロール演算子
1つ目のコマンドが異常終了したとき、2つ目のコマンドを実行(Exitステータスが0以外のとき)
cd tmp/a/b/c || mkdir -p tmp/a/b/c
&&と||演算子の組み合わせ例
cd tmp/a/b/c || mkdir -p tmp/a/b/c && tar xvf ~/newarc.tar.gz -C tmp/a/b/c
変数のQuote
bashでは下記の動作になる。zshでは全て"tmp/*"という文字列を表示
~ $ ls tmp/ a b ~ $ VAR="tmp/*" ~ $ echo $VAR tmp/a tmp/b ~ $ echo "$VAR" tmp/* ~ $ echo $VARa ~ $ echo "$VARa" ~ $ echo "${VAR}a" tmp/*a ~ $ echo ${VAR}a tmp/a
長い入力時にはエスケープシーケンスを利用
\で複数行に渡る入力が可能
$ cd tmp/d/e/f || \ cmdor> mkdir -p tmp/d/e/f && \ cmdor cmdand> tar xvf ~/archives.tgz -C tmp/d/e/f
サブシェル内のコマンドリストを実行
サンプルはtarの展開リストをadminにメールする、という処理だと思うが動かず。$()で囲むとtar -vの結果が上手く取れてないっぽい。
追記
コメントでご指摘頂きました。$()じゃなくて、()ですね。。すいません。
$()の使い方についてはウノウラボで紹介されているのでそちらを参照ください。
ウノウラボ by Zynga Japan: シェル(bash)スクリプトを書くときのTips
$ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \ > VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \ > | mail admin -s "Archive contents"
カレントシェルとしてコマンドリストを実行
$()のようにサブシェルとしてコマンドラインを実行せずに普通に同列として処理する、ってことでいいのかな?これもサンプルは上手く動かず。
追記
ここも${}と勘違いしていました。スイマセン。正しくは{}です!
$ { cp ${VAR}a . && chown -R guest.guest a && \ > tar cvf newarchive.tar a; } | mail admin -s "New archive"
xargs
参考リンク先ではfindとxargsを組み合わせて使いましょう、と書かれてます。その割にサンプルコードはfind使ってないんですけど。
$ ls -1 | xargs file December_Report.pdf: PDF document, version 1.3 README: ASCII text a: directory archive.tar: POSIX tar archive mkdirhier.sh: Bourne shell script text executable
grepでcount
wc -l使うより、grep -cの方が速いらしい
$ time grep and tmp/a/longfile.txt | wc -l 2811 real 0m0.097s user 0m0.006s sys 0m0.032s $ time grep -c and tmp/a/longfile.txt 2811 real 0m0.013s user 0m0.006s sys 0m0.005s
あと、-oオプション使うとパターンマッチングのgrepが可能
$ grep -o and tmp/a/longfile.txt | wc -l
フィールド指定でマッチング
ただ単にgrepしてしまうと、関係ない箇所がヒットして引っ張ってくることもある
$ ls -l /tmp/a/b/c | grep Dec -rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 root root 238 Dec 03 08:19 README -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar
awkでフィールド指定して比較してやればOK
$ ls -l | awk '$6 == "Dec"' -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rw-r--r-- 1 root root 238 Dec 03 08:19 README