作業を開始する前に特定の環境変数が設定されているかどうかを確認する必要がある Unix シェル スクリプトがいくつかあるので、次のような処理を行います。
if [ -z "$STATE" ]; then
echo "Need to set STATE"
exit 1
fi
if [ -z "$DEST" ]; then
echo "Need to set DEST"
exit 1
fi
これは入力量が多いです。環境変数のセットが設定されているかどうかを確認するための、よりエレガントな慣用句はありますか?
編集: これらの変数には意味のあるデフォルト値がないので、いずれかが設定されていない場合はスクリプトでエラーが発生することに注意してください。
ベストアンサー1
パラメータ拡張
明らかな答えは、パラメータ拡張の特殊な形式のいずれかを使用することです。
: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}
または、より良い方法は次のとおりです (以下の「二重引用符の位置」のセクションを参照)。
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
最初のバリアント ( のみを使用?
) では STATE を設定する必要がありますが、STATE="" (空の文字列) でも問題ありません。これはまさに必要なものではなく、代替の古い表記法です。
2 番目のバリアント ( を使用:?
) では、 DEST が設定され、空でないことが要求されます。
メッセージを指定しない場合は、シェルはデフォルトのメッセージを提供します。
この${var?}
構造は、バージョン 7 UNIX および Bourne Shell (1978 年頃) まで移植可能です。この${var:?}
構造はそれより少し新しいもので、1981 年頃の System III UNIX にあったと思いますが、それ以前の PWB UNIX にあった可能性もあります。したがって、Korn Shell や POSIX シェル (特に Bash を含む) に存在します。
これは通常、シェルのマニュアルページの「」というセクションに記載されています。パラメータ拡張たとえば、bash
マニュアルには次のように書かれています。
${parameter:?word}
Null または未設定の場合はエラーを表示します。パラメータが Null または未設定の場合、word の展開 (または word が存在しない場合はその旨のメッセージ) が標準エラーに書き込まれ、シェルが対話型でない場合は終了します。それ以外の場合は、パラメータの値が置き換えられます。
コロンコマンド
コロン コマンドは単に引数を評価して成功するだけであるということを付け加えておくべきでしょう。これは、元のシェル コメント表記法です (' #
' の前から行末まで)。長い間、Bourne シェル スクリプトの最初の文字はコロンでした。C シェルはスクリプトを読み取り、最初の文字を使用して、それが C シェル用 (' #
' ハッシュ) か、Bourne シェル用 (' :
' コロン) かを判断していました。その後、カーネルがこれに追随して ' #!/path/to/program
' のサポートを追加し、Bourne シェルに ' #
' コメントが追加され、コロンの規則は廃れました。しかし、コロンで始まるスクリプトに遭遇した場合、その理由がわかるでしょう。
二重引用符の位置
この議論について何かご意見はありますか?https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749
議論の要点は次のとおりです。
…しかし、
shellcheck
バージョン 0.4.1 では、次のメッセージが表示されます。In script.sh line 13: : ${FOO:?"The environment variable 'FOO' must be set and non-empty"} ^-- SC2086: Double quote to prevent globbing and word splitting.
この場合、どうすればよいかアドバイスはありますか?
簡単に答えると、「shellcheck
提案どおりに実行してください」です。
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
理由を説明するために、次の点を検討してください。コマンドは引数をエコーしません (ただし、シェルは引数を評価します)。引数を確認したいので、以下のコードでは の代わりに:
を使用します。printf "%s\n"
:
$ mkdir junk
$ cd junk
$ > abc
$ > def
$ > ghi
$
$ x="*"
$ printf "%s\n" ${x:?You must set x} # Careless; not recommended
abc
def
ghi
$ unset x
$ printf "%s\n" ${x:?You must set x} # Careless; not recommended
bash: x: You must set x
$ printf "%s\n" "${x:?You must set x}" # Careful: should be used
bash: x: You must set x
$ x="*"
$ printf "%s\n" "${x:?You must set x}" # Careful: should be used
*
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
abc
def
ghi
$ x=
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
bash: x: You must set x
$ unset x
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
bash: x: You must set x
$
全体の式が二重引用符で囲まれていない場合、値が$x
最初に展開され、次にファイル名のリストに展開されることに注意してください。これが修正を推奨されている点です。式が二重引用符で囲まれた形式に問題がないかどうかは確認していませんが、問題ないと考えるのが妥当です。*
shellcheck