shの覚書
#!/bin/sh foo=5 #ここで$はいらない echo $foo
=の両端に空白は許されない
環境変数も$をつけることで出力される。
#!/bin/sh echo $HOME
tcshの場合,
#!/bin/tcsh set foo = 5 echo $foo
あるいは
#!/bin/tcsh set foo = 5;echo $foo
bashの場合,
#!/bin/bash foo=5 # 代入時に空白は許されないらしい。 echo $foo
あるいは
#!/bin/bash foo=5;echo $foo
次のようにバッククォート"`"を使用することで, 各実行コマンドの出力を変数に代入できる。
foo=`echo test | sed 's/est/ree/g'` bar=`echo test | cut -c1-3` # substrの代わりになる hoge=`wc test | wc -c`
sh, bashの場合
#!/bin/sh if [ "$1" = "morning" ]; then echo "Good morning" elif [ "$1" = "afternoon" ]; then echo "Hello!" else echo "Good evening"; fi
$1はコンソールからの第一引数。
=のほかに!=も使える。否定の場合は次の書式でもよい。
if [ ! "$1" = "morning" ]; then
"["はtestと同じである。
if test "$1" = "morning"; then
複数の条件を扱いたいならば, かつ"-a"とあるいは"-o"を使用する。
#!/bin/sh foo=1 bar=1 if [ $foo = 1 -a $bar = 1 ]; then echo 1 else echo 2 fi
ファイルの存在のチェックなど特殊なオプションがある。
#!/bin/sh if [ -f "foo" ]; then echo "foo is exist." else echo "foo is not exist." fi
オプション | 意味 |
---|---|
-f | ファイルの存在 |
-d | ディレクトリの存在 |
-z | 対象が空の文字列ならtrue |
-n | 対象が空の文字列でないならtrue |
tcshの場合
#!/bin/tcsh set foo = 1 if ( $foo == 1 ) then echo 1 else echo 2 endif # endifを endif; としてはいけないらしい。
コマンドが成功して終わったかどうかをみることができる 特別な変数$?が存在する。
$ test "a" = "b" $ echo $? 1 $ test "a" = "a" $ echo $? 0 $
コマンドラインから直接行う場合
$ for f in *.{txt,html} > do > echo $f > done
そのディレクトリの拡張子がtxtとhtmlのファイルの一覧が出力される。
ファイルにしたためる場合
#!/bin/bash for f in *.{html,txt} do echo $f done
doの位置をforと同じ行にするなら
#!/bin/bash for f in *.{html,txt}; do echo $f done
forのinには, 空白で区切れば, いくらでも入れることができる。
#!/bin/bash for i in 1 2 3 4 5 6 7 8 9 do echo $i done
実行結果は, 1から9までが表示される。これを使えば, 最初の例は 次のようにも書ける。
#!/bin/sh for i in *.html *.txt; do echo $i done
whileを使う場合は次のとおり。
#!/bin/sh i=0 while [ $i -lt 10 ]; do ### [ ] の前後には空白を入れるように! echo $i i=`expr $i + 1` ### iの値を一つ増やす done;
-ltは"未満"。"以下"は-le。
ある実行の結果を行ごとに変数に入れて利用したいと きなどに, readを使用する。
#!/bin/sh # すべてのphpファイル中の2006を2007に変更する。 find . -name '*.php' -print | while read php; do sed -i 's/2006/2007/' $php done;
なお, この場合while句のブロックの変数は終了後に保存されないことに注意。 たとえば, ディレクトリの一覧を後で使いたいと思い, 次のような コードを書いたとする。
#!/bin/sh dirlist="" find . -maxdepth 1 -type d -print | while read d; do dirlist="$dirlist $d" done; echo $dirlist
最後のecho $dirlistでは何も表示されない。dirlist="$dirlist $d"の 直後に$dirlistをechoしたならばディレクトリのリストが表示される。 なぜなら, パイプを用いているためwhileはforkされた子プロセスで 実行されているからである。このようにするとパイプで標準入出力を変更する 実装が自然に行える。なお, 上記の目的を実現したい場合は次のとおり。
#!/bin/sh dirlista=`find . -maxdepth 1 -type d -print` dirlist="" for d in $dirlista; do if test "$d" != "."; then dirlist="$dirlist $d" fi done; echo $dirlist echo $dirlista
$dirlistaだけでも空白区切りのディレクトリ名一覧ができるので, 例としてふさわしいようにカレントディレクトリ(.)を抜いている。
$@は引数全てを空白区切りで渡す。$1は最初の引数, $2は2番目の引数... 以下$9まで。$0はスクリプト名。
#!/bin/bash echo $@ echo $1 echo $2 echo $3 echo $0
#!/bin/bash foo() { echo $1 } foo bbb
関数は使用する前に定義しておく必要がある。関数定義中の$1は関数の第一引数。 コンソールからの第一引数とは区別される。