通常、シェルスクリプトは一度実行されるとエラーの有無に関わらず最後まで処理を続行しようとする。
しかしこのオプションを指定することで、エラーが発生した時点でそれ以降の処理を中断するようになる。
未割り当ての変数に対して読み込みを行おうとした際に、エラーを発生させる。
実行したコマンドを全て標準エラー出力に出力する。
リダイレクト演算子 >
, >&
, <>
で既存のファイルを上書きしないようにする。
上書きをしたい場合は、リダイレクト演算子 >
の代わりに >|
を使用する。
演算子 | 意味 | 覚え方 |
---|---|---|
数値 1 -eq 数値 2 | 数値 1 と数値 2 が等しければ真 | equal to |
数値 1 -ne 数値 2 | 数値 1 と数値 2 が等しくなければ真 | not equal to |
数値 1 -lt 数値 2 | 数値 1 が数値 2 より小さければ真 | less than |
数値 1 -le 数値 2 | 数値 1 が数値 2 以下であれば真 | less than or equal to |
数値 1 -gt 数値 2 | 数値 1 が数値 2 より大きければ真 | greater than |
数値 1 -ge 数値 2 | 数値 1 が数値 2 以上であれば真 | greater than or equal to |
シェルスクリプトを実行するときのコマンドラインに引数を渡すと、シェルはそれらの値を「位置パラメータ(Positional Parameters)」に設定します。
位置パラメータは、 $1
、 $2
、…で個別の値を、 $*
、 $@
ですべての値を展開できます。
位置パラメータの数は $#
で展開できます。
$ cat test-dump.sh
##!/bin/sh
echo "$#"
echo "[$1] [$2] [$3]"
echo "[$*]"
echo "[$@]"
$ sh test-dump.sh foo bar qux
[foo] [bar] [qux]
[foo bar qux]
[foo bar qux]
シェルのマニュアルに依ってはシェルスクリプトの名前を示す変数 $0
も位置パラメータの一種のように記載しているものがありますが、この文書では含めないものとします。
位置パラメータの値はシェルスクリプト(コマンド)の引数を受け取るだけでなく、スクリプト中で任意の値を設定することができます。
ただし、代入構文 変数名=値
は使用できません。
また、 $1
など個別の値だけ設定することもできません。
位置パラメータを設定するには、組込みコマンド set
を利用して次のように記述します。
$ set -- 1st 2nd 3rd 4th
$ echo $#
4
$ echo "[$1] [$2] [$3]"
[1st] [2nd] [3rd]
$ echo "[$*]"
[1st 2nd 3rd 4th]
$ echo "[$@]"
[1st 2nd 3rd 4th]
set
コマンドは位置パラメータ値だけでなく各種シェルオプションも受け付けるため、この例で set
の最初の引数に指定しているオプション終端オプション --
が重要です。
次の例のように、 set
はハイフン -
で始まる引数をシェルオプションと解釈します。
set -a -b
実行後、現在のシェルオプション状態を示す $-
の値に ab
が追加され、位置パラメータには変化がないことに注目。
$ set aa bb
$ echo "[$*] (shell options=$-)"
[aa bb] (shell options=himBHPs)
$ set -a -b
[aa bb] (shell options=abhimBHPs)
$ set -- -a -b
$ echo "[$*] (shell options=$-)"
[-a -b] (shell options=abhimBHPs)
最初の位置パラメータの値が -
で始まる文字列でなければ --
は不要ですが、値に応じて書き分ける手間や事故を防ぐため、常に --
を指定することを推奨します。
組み込みコマンド shift
を実行すると、先頭の位置パラメータ値が破棄され、以降の値を先頭にシフトします。
$ set -- 1st 2nd 3rd 4th
$ echo "$# [$*]"
4 [1st 2nd 3rd 4th]
$ shift
$ echo "$# [$*]"
3 [2nd 3rd 4th]
位置パラメータをすべて破棄したいなら、 shift
と位置パラメータ数 $#
を組み合わせましょう。
$ set -- 1st 2nd 3rd 4th
$ echo $#
4
$ shift $#
$ echo $#
0
もしくは set
を使用しましょう。
$ set -- 1st 2nd 3rd 4th
$ echo $#
4
$ set --
$ echo $#
0
ただし、 Solaris 10 の /bin/sh
(POSIX sh 非互換)においては set --
は何の効果もなく、位置パラメータは変化しません。
POSIX sh かそれ以上の互換シェルなら問題ないと思われますが、先に紹介した shift $#
を用いたほうが無難かもしれません。
先に紹介したように $1
、 $2
、…を用います。
通常の変数展開と同じく、ダブルクオート "
で括られていれば値が展開されるだけ、括られていなければ値の展開後にワード分割やパス名店会などが適用されます。
"$*"
は、位置パラメータのすべての値の間にスペース
が差し込まれた文字列に展開されます。
$ set -- 1st 2nd 3rd 4th
$ echo "$*"
1st 2nd 3rd 4th
値の間に差し込まれる文字は $IFS
の先頭の文字(デフォルトはスペース
)が採用されます。
$ set -- 1st 2nd 3rd 4th
$ (IFS='|'; echo "$*")
1st|2nd|3rd|4th
"$*"
はダブルクオートに括られているため、展開後にワード分割はされません。
同様にパス名展開やプレース展開なども適用されません。
展開の結果は元のように個別の値にはならず、ひと塊の一つの値になります。
次のように "$*"
の展開結果を位置パラメータに設定しなおしてみると確認できます。
$ set -- 1st 2nd 3rd 4th
$ echo "$# [$1]"
4 [1st]
$ set -- "$*"
$ echo "$# [$1]"
1 [1st 2nd 3rd 4th]
位置パラメータの各値がそれぞれ個別に展開された後、個別にワード分割やパス展開などが適用されます。
$*
、 $@
どちらでも結果は変わりません。以下は $*
だけ紹介します。
次の例の echo $*
は、位置パラメータ展開の後、ワード分割により $IFS
に含まれる文字(デフォルトはスペース、タブ、改行)で分割され、 echo
コマンドの引数には 6 個の引数 foo
、 bar
、 abc
、 xyz
、 XXX
、 XXX
が渡され、結果、それが出力されます(ワード分割で空白文字が失われ、パラメータの数が元の 4 個から 6 個に増えていることに注目。
$ set -- 'foo bar' 'abc ' 'xyz ' 'XXX XXX'
$ echo $*
foo bar abc xyz XXX XXX
パラメータの数が 6 個になっていることを確認してみましょう。
$ set -- 'foo bar' 'abc ' 'xyz ' 'XXX XXX'
$ echo $#
4
$ set -- $*
6
次の例の echo $*
は、位置パラメータ展開の後、パス名展開の対象の文字 *
を含むものがパス名展開され、 echo
コマンドの引数には 2 個の引数 /bin/csh
、 /bin/tcsh
が渡され、結果、それが出力されています。
$ set -- '/bin/*csh'
$ echo $*
/bin/csh /bin/tcsh
位置パラメータの各値が展開されます。
それだけです。
パラメータの数は変化せず、ワード分割や各種展開もされません。
$ set -- ' foo bar ' hoge '/bin/*csh'
$ echo "$@"
foo bar hoge /bin/*csh
上記の実行例を一見すると、結果は "$*"
の場合と変わりないように見えますが、次の例が示すように "$@"
はもとの値と数を維持していることがわかります。
$ set -- ' foo bar ' hoge '/bin/*csh'
$ echo $#
3
$ set -- "$@"
$ echo $#
3
$ echo "[$1] [$2] [$3]"
[ foo bar ] [hoge] [/bin/*csh]
"$*"
で同様のことを実行すると次のようになります。
$ set -- ' foo bar ' hoge '/bin/*csh'
$ echo $#
3
$ set -- "$*"
$ echo $#
1
$ echo "[$1] [$2] [$3]"
[ foo bar hoge /bin/*csh] [] []
もしあなたがシェルが行うワード分割処理や各種展開処理を理解していないなら、使わないでください。
危険です。
理解していても注意して使いましょう。
位置パラメータの値に空白文字( $IFS
に含まれる文字)、パス名展開対象の文字( *
、 ?
など)、そのほかの展開対象の文字(プレース展開など)が含まれていないことが確実であれば、安全です。
位置パラメータの数に依らず、そのままの値をまとめて扱いたい場合に使用しましょう。
例えば、ログとして位置パラメータをすべてダンプしたい場合です。
log_error() {
printf "%s: ERROR: %s\n" "$0" "$*" 1>&2
}
位置パラメータの数と値を維持したまま扱いたい場合に使用しましょう。
例えば、ほかのコマンドの引数に与える場合です。
よくあるのはラッパースクリプトでの使用です。
#!/bin/sh
exec gcc -Werror "$@"
よく次のような例を見かけますが、いずれも誤動作の要因になります。
気をつけましょう。
駄目な例 1:
#!/bin/sh
## これは駄目な例です
## スクリプトの引数をワード分割、各種展開した結果がコマンドに渡ってしまいます
exec gcc -Werror $*
駄目な例 2:
#!/bin/sh
## これは駄目な例です
## スクリプトの引数をワード分割、各種展開した結果がコマンドに渡ってしまいます
exec gcc -Werror $@
zsh のデフォルト状態では $*
、 $@
は "$@"
と等価です。
zsh オプション GLOB_SUBST
、 SH_WORD_SPLIT
の解説を参照してください。
globsubst
(GLOB_SUBST
)- クオートなしの変数展開時に展開後の値でパス名展開する
- zsh のデフォルトはパス名展開しない
shwordsplit
(SH_WORD_SPLIT
)- クオートなしの変数展開時に展開された値を空白文字で分割(ワード分割)する
- zsh のデフォルトは空白文字分割しない
globsubst
と shwordsplit
がよくわからない人のためのデモ:
$ zsh -c 'v="/*"; echo $v; set -o GLOB_SUBST; echo $v'
/*
/bin /boot /dev /etc /home /lib /lib32 /lib64 /lost+found /media /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var
$ zsh -c 'v=" foo "" bar "; echo $v; set -o SH_WORD_SPLIT; echo $v'
foo bar
foo bar
#!/usr/bin/env bash
set -e
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
シェルスクリプトの終了時にディレクトリごと削除される。
#!/usr/bin/env bash
set -e
tmpdir=`mktemp -d`
trap "rm -rf $tmpdir" 0
echo dummy > $tmpdir/dummy.txt