用語集
シェルスクリプト
コマンド実行を自動実行するためのファイル (if/else/foreach/while/case/switch)
最終更新
シェルスクリプトは
#!/bin/sh
echo "Hello World"
などと、シェルが解釈できるコマンドを羅列したファイルのことを指す。
sh が解釈できるシェルスクリプトのことを「sh スクリプト」(シェルスクリプトまたはエスエイチスクリプト)、csh が解釈できるシェルスクリプトのことを「csh スクリプト」(シーシェルスクリプト) と呼ぶことがある。
●シェルスクリプトの作り方
vi や emacs 等のエディタで
#!/bin/sh
echo "Hello World"
というファイルを sample.sh などのファイル名で保存する。その後、
として実行権限を付与することで、
% ./sample.sh
Hello World
と実行できる。
●sh・bash でのシェル変数セット
単純に文字列を代入し、表示する。
"=" の前後に空白を入れて下記のようにするとうまく動かない。引数 "=" と "FUGA" を渡して "hoge" コマンドを実行する、と解釈されるためである。
改行コード入りの文字列を代入し、表示する。変数を利用する際、"" で囲むことで改行が維持される ("" で囲まないと IFS により 1行になってしまう)。
hoge="abc
def"
echo "$hoge"
●sh・bash での変数置換
${var} 変数の値をそのまま返す。
${var:-word} 変数が未定義か空文字の場合、word を返す ($var に保存しない)
${var:=word} 変数が未定義か空文字の場合、word を返す ($bar にも保存する)
${var:?word} 変数が未定義か空文字の場合、標準エラー出力に word を出力し、スクリプトを終了する。
${var:+word} 変数がセットされている場合、word を返す。
●sh・bash での一定回数のループ
i=0
while [ $i -lt 5 ]; do
echo $i
i=`expr $i + 1`
done
seq コマンドを使ってもよい。
for i in `seq 1 10`; do
echo "No: $i"
done
これは bash のみだと思うが、下記のようにも書ける。
for i in {1..10}; do
echo "No: $i"
done
これも bash のみだと思うが、for (( expr1 ; expr2 ; expr3 )) という書き方もできる。
for (( i=0 ; i<10 ; i++ )); do
echo "No: $i"
done
●sh・bash での行単位の処理
コマンド実行結果から:
ls -l | while read line; do
echo $line
done
ファイルから:
while read line; do
echo $line
done < file.txt
ヒアドキュメントで:
while read line; do
echo $line
done <<END
hoge
fuga
END
●bash での配列初期化 【2018-12-28追加】
myarray=()
→ 空配列
myarray=(a0 a1 a2)
→ インデックス0番目に a0、1番目に a1、2番目に a2 を設定
myarray=([0]=a0 [1]=a1 [3]=a3)
→ インデックスを明示的に指定。
●bash での配列をすべて表示 【2018-12-28追加】
要素のみでよいなら下記のようにする。
myarray=(a0 a1 a2)
echo ${myarray[@]}
→ 結果は a0 a1 a2
ループで全要素を取得する例。
for i in "${myarray[@]}"; do
echo "$i"
done
インデックスから全要素を取得する例。
myarray=([0]=a0 [1]=a1 [3]=a3)
echo ${!myarray[@]}
ループでまわす場合は下記。
for i in "${!myarray[@]}"; do
echo "$i": "${myarray[$i]}"
done
●sh・bash でのファイル名の取得
ファイルグロブを使って:
for file in *.txt; do
echo $file
done
コマンドの実行結果を使って:
for file in `ls | grep -v abc`; do
echo $file
done
for file in `find . -name \*.txt`; do
echo $file
done
●sh・bash での if 文
if [ $var = "abc" ]; then
echo "var is abc"
elif [ $var = "def" ]; then
echo "var is def"
else
echo "var is not abc nor def"
fi
「=」以外にも、「!=」「>」「<」や、「-f」「-d」などのファイルテスト演算子を使うことができるが、test コマンドを参照してほしい。
●sh・bash での continue・break
continue・break は for・while から脱出・次ループへ移動を行う。
などとすることで、内側から何個目の for・while に対しての指示なのかを指定できる。
と
は、それぞれ等価である。
for file in `ls`; do
if [ $file = "hoge.txt" ]; then continue
if [ $file = "fuga.txt" ]; then break
done
●sh・bash での switch 文
case $var in
hoge)
echo "var is hoge"
;;
foo|bar)
echo "var is foo or bar"
;;
*)
echo "var is unknown"
;;
esac
●sh・bash での関数
sh・bash では、下記のようにして関数を作成することができる。
myfunc () {
echo "myfunc の処理"
}
bash ならば関数定義の先頭に function をつけてもよい (function をつけてもつけなくても挙動は同じ)。
function myfunc () {
...
}
定義した関数を実行するには、下記のように単に関数名を書けばよい (呼び出し時にカッコなどは不要)。
引数を処理する場合、コマンドパラメータ取得時のように $#・$1・$2 などの変数を使うことができる。
myfunc_arg () {
echo "引数の個数: $#"
echo "引数1 $1"
echo "引数2 $2"
}
myfunc_arg abc def
上記の実行結果は下記のようになる。
% ./sample.sh
引数の個数: 2
引数1 abc
引数2 def
●sh・bash の関数内のローカル変数
bash と一部の sh では、local コマンドを使うことで、ローカル変数の定義・宣言ができる。
myfunc () {
local var="1"
}
詳細は local コマンドのページを参照のこと。
$? は、直前のコマンドの結果で上書きされるので、
command
echo $?
if [ $? != 0 ]; then 〜
はうまく動かない。echo の結果 (ほとんどの場合 0) で上書きされるからである。ちなみに変数代入も $? を上書きするので、下記もうまくうごかない (if の判定は変数代入の結果をチェックしていることになる)。
command
ret=$?
if [ $? != 0 ]; then 〜
●sh・bash で、Yes か No を答えさせる
while [ 1 ]; do
/bin/echo -n "Type Yes/No: "
read line
case $line in
[yY][eE][sS])
echo YES; break
;;
[nN][oO])
echo NO; break
;;
esac
done
bash であれば bash の内部コマンド select コマンドで入力を受け取ることも検討してみるとよい。
●sh・bash での計算
$(( 〜 )) で囲むことで、計算を行う。内部では変数を $x ではなく x と書ける ($x と書いても動くようだが)。
x=10
y=20
z=$(( x + y * 3 ))
echo $z
→ 70 となる
bash の場合、代入する変数を declare -i にて数値型であることをあらかじめ宣言しておけば、カッコなどが不要になる。
declare -i z
x=10
y=20
z=x+y*3
echo $z
なお、世の中一般においては csh や tcsh でシェルスクリプトを書くことはよくないとされている。当ページ管理人としてはコマンドラインから使う分には tcsh が好きなので聞こえないふりをしてきた (そして Perl や Python でスクリプトを書いてきた)。
vi や emacs 等のエディタで
#!/bin/csh -f
echo "Hello World"
というファイルを sample.csh などのファイル名で保存する。その後、
として実行権限を付与することで、
% ./sample.csh
Hello World
と実行できる。
[[csh・tcsh での環境変数セット #csh-env-variable-set
●csh・tcsh での if 文
if ( $var = "abc" ) then
echo "var is abc"
else if ( $var = "def" ) then
echo "var is def"
else
echo "var is not abc nor def"
endif
●csh・tcsh での continue・break
continue・break は foreach・while から脱出・次ループへ移動を行う。csh の continue・break は、最も内側のループにしか効かない。
foreach file (`ls`)
if ( $file = "hoge.txt" ) then
continue
endif
if ( $file = "fuga.txt" ) then
break
endif
end
●csh・tcsh での switch 文
switch ($var)
case "hoge":
echo "var is hoge"
breaksw
case "foo":
case "bar":
echo "var is foo or bar"
breaksw
default:
echo "var is unknown"
breaksw
endsw
●余談
シェルスクリプトのことを指して「シェル」と呼んではいけない。本人は略しているだけのつもりかもしれないが、端から見るとシェルとシェルスクリプトの区別が付いていないように見える。よくわかっていない人が
「ファイルが消えた原因はシェルのバグです」
と主張するとき、原因は sh や csh のバグではなく、ほとんどの場合その人が書いたシェルスクリプトのバグにすぎない。当ページ管理人のネット上・実社会での観測結果によると、「シェルスクリプト」を「シェル」と呼ぶ人のスキルは著しく低い傾向がある。