1. ホーム
  2. bash

[解決済み] Unixのシェルスクリプトで環境変数が設定されていることを確認する簡潔な方法は何ですか?

2022-03-20 23:49:44

質問

私はいくつかの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

というのは、多くのタイピングが必要です。環境変数のセットが設定されているかどうかをチェックするための、もっとエレガントなイディオムはないでしょうか?

EDIT: これらの変数には意味のあるデフォルト値がないことを明記しておきます - どれかが未設定の場合、スクリプトはエラーになるはずです。

どのように解決するのですか?

パラメータ展開

明白な答えは、パラメータ拡張の特別な形式の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=""(空文字列)でもOKです - 正確にあなたが望むものではありませんが、代替となる古い記法です。

2つ目のバリエーションは :? ) DESTが設定され、空でないことが必要です。

メッセージを指定しない場合、シェルはデフォルトのメッセージを提供します。

${var?} は、UNIX のバージョン 7 と Bourne Shell (1978 年頃) にまで遡って移植可能です。 そのため ${var:?} という構文は、もう少し新しいものです。1981年ごろのSystem III UNIXにあったと思いますが、それ以前からPWB UNIXにあったかもしれません。 そのため、Kornシェルや、BashをはじめとするPOSIXシェルにも含まれている。

通常、シェルの man ページにある パラメータ展開 . 例えば bash のマニュアルにはこうあります。

${parameter:?word}

Nullまたは未設定の場合、エラーを表示する。 パラメータが NULL または未設定の場合、word の展開(word が存在しない場合はその旨のメッセージ)を標準エラーに書き出し、シェルが対話型でない場合は終了します。 それ以外の場合は,パラメータの値が代入されます。

Colonコマンド

コロンコマンドは、単に引数が評価されて成功するものであることを付け加えておく。 これは、シェルのコメント記法の原型となるものです(' # ' から行末まで)。 長い間、ボーンシェルのスクリプトは、最初の文字にコロンを使っていました。 Cシェルはスクリプトを読んで、その最初の文字でCシェル用かどうかを判断していた(' # ' ハッシュ)または Bourne シェル(' : コロン)。 その後、カーネルがこの動きに加わり、' #!/path/to/program を取得し、ボーンシェルが' # というコメントが出て、コロンの慣習は廃れていきました。 しかし、もしあなたがコロンで始まるスクリプトに出会ったら、その理由がわかるでしょう。


二重引用符の位置

ブロン で尋ねた。 コメント :

この議論について、何かご意見はありますか? 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 は修正することを推奨しています。 式がダブルクォーテーションで囲まれた形でも異議を唱えないかどうかは検証していませんが、問題ないだろうと考えるのが妥当でしょう。