CUIの世界で暮らす場合、シェルの使いこなしで作業効率は桁違いに変わる。シェルは一種類だけではないが、シェルスクリプトの観点からはsh系とcsh系に分けられる。sh系であるbash(zshでもOK?)をメインに使ってみることにする。純粋な /bin/sh を使うと、declareが使えず、exprとなるのが面倒。 *link [#j4378a5b] -[[ステップ・バイ・ステップ・シェルスクリプト:http://www.atmarkit.co.jp/flinux/index/indexfiles/shellsindex.html]] -[[bashで始めるシェルスクリプト基礎の基礎:http://www.atmarkit.co.jp/flinux/rensai/theory08/theory08a.html]] -[[シェルスクリプトの基礎:http://warp.syns.net/10/]] *実例 [#uc500115] あえて全部別々に記述してみた。 **jpegファイルで、大文字の拡張子を小文字にする(JPG -> jpg) [#j48fd7c2] for filename in *.JPG do mv ${filename} ${filename%JPG}jpg done **ダメ写真を削除したなどで、連番が歯抜けとなったjpegファイル群に番号を振りなおす [#k74bfee7] declare -i num num=1 for filename in *.jpg do mv $filename `printf "image%03d.jpg\n" $num` num=$num+1 done **プレビュー用にリサイズしたものをImagemagikで作り、previewディレクトリに保存。 [#p1c3131f] for file in *.jpg do convert -geometry 160x120 $file ./preview/$file done **プレビュー用画像をクリックしたら元の画像が出てくるようなHTMLファイルをつくる。 [#jf630723] declare -i number declare -i residue number=1 echo "<body>" echo "<h1>put a title in EUC....</h1>" echo "<hr>" echo "" echo "<table cellpadding=\"20\">" for filename in *.jpg do residue=$number%3 if [ $residue -eq 1 ] then echo "<tr>" fi echo " <td align=\"center\">" echo " <a href=\"$filename\"><img src=\"preview/$filename\" alt=\"\" width=160 height=120 boarder=0></a>" echo " <br> " ## comment echo " </td>" if [ $residue -eq 0 ] then echo "</tr>" fi number=$number+1 done echo "</table>" echo "</body>" **連番 [#me7ef5f5] 参考 - [[シェルスクリプト総合 その1:http://pc8.2ch.net/test/read.cgi/unix/1101820646/]] 例えばshなら i=1 while test $i -le 10 do echo $i i=`expr $i + 1` done とする。seqコマンドを使っても $ seq -s ' ' 1 10 1 2 3 4 5 6 7 8 9 10 $ seq -f %03g -s ' ' 1 10 001 002 003 004 005 006 007 008 009 010 と、同様なことができる。整形はprintfコマンドでもOK。 *基本 [#l3ba1143] スクリプトはコマンドラインから入力しても良いが、慣れないうちは別ファイルとした方が良い。最もお手軽には、コマンドを列挙したファイル hoge.sh を用意して $ bash hoge.sh などとする。あるいはファイル冒頭に #!/bin/bash などとシェルへのパスを書き、ファイル自身に実行属性を与えても良い。 **引数 [#lb551019] $1, $2, ... としてコマンドラインの引数を参照できる。他にも $0 # スクリプトの名前 $# # 引数の数 $* # 全ての引数 など。 **変数 [#x02caf3b] ***bash [#w275a4ba] 変数は基本的に文字列として扱われる。数値としたいならdeclareで指定する。変数の中身を参照する場合は冒頭に$を付す。演算子の両脇に空白を含めてはならない! declare -i var1 var1=10 var2=20 var1=$var1+1 var2=$var2+1 echo var1,var2,$var1,$var2 なるスクリプトの出力結果は var1,var2,11,20+1 となる。var2は文字列となっていて、算術演算が反映されていない。 ***sh [#dff245f0] i=1 i=`expr $i + 1` などとする。exprの演算子の両脇に空白が必要。 **パターンマッチ [#e9f19fb8] * 任意の文字列 ? 任意の一文字 [...] カッコ内のいずれか これを利用して、文字変数valをいじったものを返すことができる。 ${val#pattern} val前方から最短マッチ部分を除く ${val##pattern} val前方から最長マッチ部分を除く ${val%pattern} val後方から最短マッチ部分を除く ${val%%pattern} val後方から最長マッチ部分を除く よく使うのは以下の2種類 mypath=/path/to/somewhere/foo.txt echo ${mypath%.*} # 拡張子を除く。/path/to/somewhere/foo echo ${mypath##/*/} # ファイル名のみを得る。foo.txt **制御文 [#f7f41b1b] ***if文 [#v67feea7] 以下の様に記述。カッコ前後には空白を挿入すること。 str=hoge # <-- hoge or fuga if [ $str = hoge ] then echo hoge! elif [ $str = fuga ] then echo fuga! else echo neither! fi 条件式に使う等号は、両端に空白を挿入せねばならないみたいだ。 |s1 = s2 | 文字列s1とs2が等しい | |s1 != s2 | 文字列s1とs2が等しくない | |v1 -eq v2 | 数値v1とv2が等しい | |v1 -ne v2 | 数値v1とv2が等しくない | | -e file | fileが存在する | ***for文 [#z406f63d] このループは、リスト中の要素に対してコマンドを繰り返し実行して、対象が無くなったら勝手に終わるので、Cなどのfor文とは雰囲気が違う。しかし例えば「カレントディレクトリ中のjpegファイル全てに対し○○○を実行する」なんて処理は以下の様に非常に簡潔に書ける。 for filename in *.jpg do ○○○ # <--変数filenameを使って何かをする done ○○○を'echo $filename'などとすると、jpegファイル名が列挙されるわけである。