次のようなifステートメントがあるとします。
if [ $(false) ]; then
echo "?"
fi
これにより、「?」は印刷されません(条件が偽です)。ところで、次のような場合には「?!」が出力されますが、なぜでしょうか。
if [ $(false) -o $(false) ]; then
echo "?!"
fi
答え1
$(false)
falseと評価されず、空の文字列を生成します。引用がないので、
if [ $(false) ]; then
次のように評価
if [ ]; then
[
空の式は偽なので、これは偽です。
if [ $(false) -o $(false) ]; then
次のように評価
if [ -o ]; then
これいいえ-o
演算子を使用すると、-o
単一の文字列を含む式で評価されます。[
これらの式はtrueなので、then
ステートメントの一部がif
実行されます。
バラよりPOSIX仕様test
、特に:
演算子の優先順位と生成される戻り値を決定するために使用されるアルゴリズムは、テストする引数の数に基づいています。 (ただし、「[...]」形式を使用する場合は、最後のパラメータ<右角括弧>をアルゴリズムに含めないでください。)
次のリストでは、$ 1、$ 2、$ 3、および$ 4はテストするパラメータを示しています。
引数 0 個:
false(1) を終了します。
パラメータ1:
$ 1がnullでない場合はtrue(0)を返し、そうでない場合はfalseを返します。
test
演算子は、2つ以上の引数が指定されている場合にのみ考慮されます。
コマンドの終了ステータスを条件として使用するには、コマンドの置き換えまたは次の項目に入れないでください[ ]
。
if false; then
そして
if false || false; then
また参考にしてくださいtest
-a
演算子は-o
廃止され、信頼できません。;シェルの&&
AND||
演算子を使用する必要があります。例えば
if [ "$a" = b ] || [ "$a" = c ]; then
答え2
素晴らしい答えで指摘した内容を繰り返しません。寄稿者: @StephenKittそしてこんにちはここでは、書き込みの意味にのみ焦点を当てますif [ $(cmd) ]; then...
。
まずこれでは[
ないことを知っておいてください。POSIXsh
演算子とも呼ばれる別のユーティリティです。test
ここで、文法の //// 文のif
部分に使用されます。if
then
elif
else
fi
sh
言語。
その使命は、引数を条件式で評価することです。たとえば、、、、、およびを[
パラメータとして受け取るか、、、、およびを受け取ると、次のように解釈さa
れるため、false/失敗した終了ステータスを返します。=
b
]
test
a
=
b
「'a'と'b'は同じ文字列ですか?」条件式
[
通常、//ステートメントの一部として使用されるか、if
//または//ステートメント内の唯一のコマンドとして使用されますが、これらのステートメントである必要もなく、単一のコマンドを呼び出す必要もありません。if
then
elif
else
fi
while
do
done
until
do
done
[
実行とは、を使用して結果を拡張し、コマンドを別の引数として呼び出すことを[ $(cmd) ]
意味します。その後、これらのパラメータは条件式として解釈され、結果に応じてtrueまたはfalseを返します(式が理解できない場合はfalse)。[
[
$(cmd)
]
[
POSIX shは$(cmd)
すべての末尾の改行文字を削除して標準出力に拡張しcmd
、引用符がなくリストコンテキストにあるため、IFS分割後にワイルドカードが適用されます(その出力にNUL文字がある場合の動作は指定されません)。
だからif [ $(cmd) ]
、またはtest $(cmd)
何の意味もありません。
それは質問をするのと同じです:「分割+グローブされると、出力がcmd
trueと評価される有効な条件式を構成しますか?」
たとえば、cmd
出力合計に偶然含まれていて、a,*
現在の作業ディレクトリに2つのファイル(1つは名前が付けられ、もう1つは名前付き)が含まれている場合、そのファイルは引数として、、、、を使用して呼び出されます。幸い、これは有効な条件式ですが、falseを返す条件式はそうではありません。$IFS
,
=
b
[ $(cmd) ]
[
[
a
=
b
]
a
b
$ cd "$(mktemp -d)"
$ touch = b
$ cmd() { echo 'a,*'; }
$ IFS=,
$ set -o xtrace
$ if [ $(cmd) ]; then echo yes; else echo no; fi
++ cmd
++ echo 'a,*'
+ '[' a = b ']'
+ echo no
no
今[ "$(cmd)" ]
より意味があります。 Quoteコマンド置換は、NULを出力するときに未指定のまま残っている末尾の改行文字の削除を防ぎませんがcmd
、分割+globおよびnullの削除を防ぎます。したがって、[
3つの引数が常に渡されます。、、[
末尾の改行が削除された出力、および。横には、そのパラメーターが空の文字列でない場合にのみtrueを返すパラメーターがあります。これはと同じです。cmd
]
[
]
[
[ -n "$(cmd)" ]
だからそれは次のように言うのと同じです:"cmd
改行文字(またはNUL)以外の文字を1つ以上出力してください。。テキストを出力するコマンドの場合(テキストが行で構成され、NULを含まないことが保証されています)cmd
「空白以外の行を1つ以上出力しますか?」
短い出力を除くと、出力全体を読み取って転送する前にメモリに保存されるため、これは非効率的な方法でこれを行います[
。
if cmd | grep -q .; then...
grep
終了するので、より効率的です。本物少なくとも1つの文字を含む行を見つけた場合。
その場合、最終的にシェルがクラッシュしますcmd
。yes
if [ "$(cmd)" ]
十分な保存エラーが発生すると、if cmd | grep -q .
yesはすぐに出力されます(yes
SIGPIPE信号で終了します)。
成功するかどうかをテストするには、cmd
出力の有無にかかわらず、次のようにします。
if cmd; then
echo cmd succeeded
else
echo cmd failed
fi
if $(cmd); then
話すべきもう一つのコード例です。しかし、cmd
存在する例は少し異なりますfalse
。
繰り返しますが、末尾の$(cmd)
改行文字は削除され、分割+グローブの影響を受けます。ただし、今回は生成された単語が[
/test
ユーティリティに渡されず、これらの単語のうち最初の単語(存在する場合)が実行されるコマンドとして処理され、すべての単語が引数として渡されます。
したがって、cmd
出力echo:hello:world
と$IFS
インクルードが引数としておよび引数として実行され、stdoutに正常に書き込むことができると仮定すると、true :
/成功を返すため、その部分が実行されます。echo
echo
hello
world
echo
"hello world\n"
then
cmd
出力が生成されない場合、または改行とIFS空白文字のみが生成されると、単語はまったく生成されないため、$(cmd)
他のコマンドは実行されず、この時点ではcmd
ステートメントの終了状態が重要ですif
。
存在する:
if $(false); then
echo yes
else
echo no
fi
no
出力がfalse
生成されなかったため、コマンドが実行されなかったために出力され、終了ステータスによってそのセクションが実行されるかどうかがfalse
決まります。else
存在する:
if $(echo true; false); then
echo yes
else
echo no
fi
、または文字を含まないと$IFS
想定され、最終的に実行され、終了ステータスがステートメント内の分岐を決定します。t
r
u
e
true
if