2017-02-10 13 views
1

私はシェルスクリプトに慣れていて、面白くて説明できない動作を見つけました。次のコードでは、最初のforループは正しく実行されますが、2番目のforループは正しく実行されません。Bash forループの構文

declare letters=(a b c d e f g) 
for i in {0..7}; do 
    echo ${letters[i]} 
done 
for i in {0..${#letters[*]}}; do 
    echo ${letters[i]} 
done 

次のエラーでループが発生する第二:コードは、たとえ失敗した私を混乱させる何

syntax error: operand expected (error token is "{0..7}") 

${#letters[*]}がはっきり番号7にしかし、これにもかかわらず、正しく、評価を取得していることです{0..7}と同じループが完全に正常に動作することがわかりました。

この理由は何ですか?

私はOS X 10.12.2、GNU bashバージョン3.2.57を使用しています。

+0

{0..7}を使用すると、 1 2 3 4 5 ...などに拡張されます。 あなたが{0 .. $ {#letters [ ]}これは文字列に展開されます "{0..7}"あなたは反復できません – Yarden

答えて

3

パラメータ展開前にブレース拡張が行われるため、変数を範囲の一部として使用することはできません。

値のリストにアレイを展開し、

for letter in "${letters[@]}"; do 
    echo "$letter" 
done 

またはリストへの配列のインデックスを展開します、これら2つのコメント(おかげ)で述べたよう

for i in ${!letters[@]}; do 
    echo "${letters[i]}" 
done 

アプローチはまばらな配列にも対応します。配列がの値をすべてのインデックス0${#letters[@]}の間に定義していると常に考えることはできません。

+1

これらは疎配列にも対応しています。配列が0と '$ {#letters [@]}'の間のすべての*インデックスの値を定義していると常に考えることはできません。 – chepner

+0

@chepnerありがとうございました。 –

5

パラメータ拡張の前にブラケットの拡張が行われます(詳細はman bashのEXPANSIONSを参照)。したがって、リテラルのみで機能します。つまり、変数で中括弧拡張を使用することはできません。

はあなたがCスタイルのループを使用することができます

seqよう

for ((i=0; i<${#letters[@]}; i++)) ; do 
    echo ${letters[i]} 
done 

または外部コマンド:

for i in $(seq 1 ${#letters[@]}) ; do 
    echo ${letters[i-1]} 
done 

しかし、あなたは通常、インデックスを必要としないが、代わりに1要素をループ自分自身、@ TomFenechの答えを参照してください。彼はまた、インデックスのリストを取得する別の方法を示しています。

7ではなく、{0..6}であることに注意してください。