forループ構文

forループ構文

どして

for i in {1..5}; do x="${i}" echo "$x"; done

出力されない

1
2
3
4
5

?

これを実行する正しい方法は何ですか?

(テスト済みfor i in {1..5}; do x=$(i) echo "$x"; done

-bash: i: コマンドが見つかりません

その他)

答え1

質問通りに答える

、、、、がfor i in {1..5}; do x="${i}" echo "$x"; done出力されないのはなぜですか?12345

その理由は、実行中に演算が評価される順序に関係しています。このコマンドを見てください

x="${i}" echo "$x"

これは

  1. 変数をその値に置き換える
  2. 変数に一時的な値を割り当てるx
  3. コマンドを実行する

つまり

  1. x=1 echo ""(またはx=2 echo ""、など)
  2. このコマンドの実行中は、x値に設定されます1
  3. 次のコマンドが実行されます:echo ""

おそらく、このコマンドは に値を割り当てx、その値を出力するという 2 つの命令を意味していたのでしょう。しかし、シェル構文では、記述したコードは完全に合法的なので、シェルは問題なくそれを実行しました。

答え2

次の 2 つの質問に対する回答を求めました。

  1. 現在のコードが期待どおりの出力を生成しない理由について説明を求めました。

  2. 期待どおりの出力が生成されるようにコードを正しく記述する方法を尋ねました。

あなたのコードを見ると、なぜそのようにコードを書いたのか、2 つの説明が考えられます。

  1. 少し混乱があるかもしれないがforループの構文

  2. 評価の順序については、多少混乱があるかもしれないが、簡単なコマンド

forループ構文

最初のケースでは、変数の割り当ての後にセミコロンがないと思われます。for ループを 1 行で記述したい場合は、ループ本体の各コマンドの後にセミコロンを置く必要があります。代わりに、次のコードを試してください。

for i in {1..5}; do x="${i}"; echo "$x"; done

別の方法としては、セミコロンの代わりに改行を使用した複数行構文を使用して for ループを記述する方法があります。

for i in {1..5}
do
x="${i}"
echo "${x}"
done

セミコロンと改行を組み合わせて使用​​することもできます。例:

for i in {1..5}; do
x="${i}"; echo "${x}"
done

単純なコマンドの評価

2番目のケースでは、コマンドのプロローグでの変数の割り当て(つまり割り当てx="$i")が、コマンド本体での変数の展開(つまり${x}inの展開echo "${x}")の前に行われると想定していたと思います。しかし、実際にはそうではありません。これを確認するには、次のページを参照してください。シンプルなコマンド拡張Bashマニュアルまたは簡単なコマンドに関するサブセクションの中にPOSIX仕様これら両方の参考文献には次の一節が含まれています。

「単純コマンド」とは、任意の順序でオプションの変数割り当てとリダイレクトのシーケンスであり、オプションで単語とリダイレクトが続き、制御演算子で終了します。

与えられた単純なコマンドを実行する必要があるとき(つまり、AND-ORリストや場合ステートメントが単純なコマンドをバイパスしていない場合、次の展開、割り当て、およびリダイレクトはすべてコマンド テキストの先頭から末尾まで実行されます。

  1. 変数の割り当てまたはリダイレクトとして認識される単語は、シェル文法規則手順 3 と 4 で処理するために保存されます。

  2. 変数割り当てまたはリダイレクトではない単語は展開されます。展開後にフィールドが残っている場合、最初のフィールドはコマンド名と見なされ、残りのフィールドはコマンドの引数と見なされます。

  3. リダイレクトは、以下に記載されているとおりに実行されるものとする。リダイレクション

  4. 各変数の割り当ては、値を割り当てる前に、チルダ展開、パラメータ展開、コマンド置換、算術展開、および引用符削除のために展開される必要があります。

ステップ 2 ではコマンドの変数の展開が行われますが、ステップ 1 では変数の割り当てがステップ 3 と 4 まで保存されることが示されています。したがって、式は割り当てが行われる前echo "${x}"に展開されます。これが、空の出力が得られた理由です。echo ""x="${i}"

このトピックに関する詳細な議論については、次の投稿を参照してください。

答え3

では、のzsh3 番目の形式である Bourne 演算子を使用し、代入は無条件になります (var が設定されていないか空の場合のみではなく)。${var::=value}${var=value}${var:=value}

for i in {1..5}; do echo ${x::=$i}; done

または:

for i ({1..5}) echo ${x::=$i}

bash

set -o posix # so the value of x remains after eval returns
for i in {1..5}; do x=$i eval 'echo "$x"'; done

つまり、$xその展開を含むコードが評価される時点で設定されている必要があります。

ここでのような 10 進整数値の場合は、次のようにすることもできます。

for i in {1..5}; do echo "$((x = i))"; done

または、空の文字列を${var:=value}設定した後で、常に Bourne 演算子を使用することもできます。x

for i in {1..5}; do x=; echo "${x:=$i}"; done

関連情報