このコマンドで{}が機能しないのはなぜですか?

このコマンドで{}が機能しないのはなぜですか?

.以下の コードスニペットから: {}()

#!/bin/bash
set -e
echo "two">file.txt
ARRAY=(one two three)
rc=0
for i in ${ARRAY[@]}; do
    echo "grepping $i "
    #grep "$i" file.txt || (echo "failed grep" && exit 1) <--1
    #grep "$i" file.txt || {rc=$? && echo "failed grep"}  <--2
    grep "$i" file.txt || (rc=$? && echo "failed grep")   <--3
done

exit $rc  

コマンド2は動作しない唯一のコマンドです。しかし、私はそれがうまくいくと予想しており、コマンド1は許可された答えに従ってスクリプトを終了しません。ここ
何が起こっているのかを説明できる人はいますか?

答え1

bashほとんどのPOSIXシェルでは、while(とはシェル構文の特殊表示文字です(、、、、、...)などの複数文字表示の一部を含む、発生するたびに特別に処理されます)。組み合わせは、inなどの特殊表示文字を使用するか、特殊またはフォームに使用されます。(($(<($((<#(({}${{x,y}{x..y}

echo )whileはエラーが発生しますが、echo }出力がないため、inを閉じることは不可能であることがわかります。}}{echo}{

具体的{}キーワード良いwhile、、、。time!コマンドが必要な場合にのみ(最初の近似で)別の単語としてのみ表示できます。

{echo次のキーワード{echoではなくコマンドになります。キーワードの後に​​itが来るのではなく、コマンドと同じです。{echowhile[while[while[

とが分離されてコマンド位置にある場合、またはを使用できますが、は使用できません{ echo;}{<file cat;}{}{echo}

しかし、いくつかの例外があります。通常、リダイレクト以外には何も起こらず、コマンドの位置にない{(echo test)}閉じた後もこれが機能することがわかります。指揮ポジションにいない二人目も同様です。)}{ { echo; } }}

{ echo; ! }または{ echo; time }ksh93では動作しますが、動作しません(コマンド位置にbashあっても)。}

1つの例外は、可能な場合とトークンとして認識zshしようとすることです。つまり、指揮位置にあり、特定の限られた状況にあるときです。そこでは動作しますが、たとえば動作しません。 bash / kshの代わりにそこのようです。{}{echo}{{echo}}{{echo} }{echo,foo}{ echo,foo;}echo foo

<file {head;head}動作しますzshが、他のシェルでは動作しません。

これはIGNORE_BRACESオプションによってIGNORE_CLOSE_BRACES制御されます。

答え2

コロンで{}区切られた型複合ステートメントのプレースホルダーであり、変数の更新が中括弧の外に反映されないサブシェルコンテキストを作成します。bash()

$?grepあるいは、他のシェルコマンドを使用するときに戻りコード値を台無しにする必要さえありません。0コンソール出力を抑制することで、if条件で直接終了コードを使用できます(通常は成功した場合はコマンドを返します)。フラグをgrep有効にすると、-qこれを行うことができます。

if grep -q "$i" file.txt; then
    printf "grep suceeded\n"
else
    printf "grep failed\n"
fi

終了コードを手動で保存するには、複合ステートメントを使用するのが正しいです(ここではサブシェルの使用は機能しません!)。複合文を次のように終了します。;

grep "$i" file.txt || {rc=$? ; echo "failed grep" ; }

これで終了コードを使用できますrc。あるいは、より簡単には、echo自体で変数を使用することもできます。

grep "$i" file.txt || echo "failed grep with rc: $?"

sub-shell を使用して回答に追加するには、()変数コンテキストを保存することをお勧めします。いいえ良い習慣です。リンクされたコマンドが完了した直後にシェルが終了します。

たとえば、次のような単純な文字列同一性操作を使用します。

str='foo'; rc=0
[[ $str == *doo* ]] || { rc=$?; echo "string comparison failed" ; }
echo "$rc"

値は正しく反映されrcますが、サブシェルの場合は機能しません。

str='foo'; rc=0
[[ $str == *doo* ]] || ( rc=$?; echo "string comparison failed" )
echo "$rc"

サブシェル内で0設定したときに返す必要がある値を反映します。1


[実際の問題とは無関係]

常に配列拡張を引用する必要があります。そうしないと、スペースやその他の特殊文字を含む配列要素を単一の単語として扱うことなく別の単語に分割します。

for i in "${ARRAY[@]}"; do

関連情報