24136


配列変数をfor文に渡して、配列要素にアクセスしたいのですが、うまくいきません。  
このようなアクセスはできないのでしょうか？

[code]

    list1=(aa bb)
    list2=(cc dd)
    
    for l in list1 list2
    do
      echo $l[0];
      echo $l[1];
    done
    
[/code]

**実行結果**

[code]

    list1[0]
    list1[1]
    list2[0]
    list2[1]
    
[/code]

**期待する結果**

[code]

    aa
    bb
    cc
    dd
    
[/code]


CC BY-SA 3.0
2016-04-19T00:47:29.817
24130
2019-05-09T06:38:52.243
2016-04-19T03:36:39.910
15147
15147
question
bash shellscript sh
シェルスクリプトのfor文で配列変数を使いたい。


bashのfor文は`in`の後に記述されたものを順番に実行します。そのため、`l`に入れる要素が`in`のあとに順番に並んでいる必要があります。

[code]

    for l in "${list1[@]}" "${list2[@]}"
    do
      echo $l
    done
    
[/code]


CC BY-SA 4.0
2016-04-19T01:52:42.177
24132
2019-05-09T06:38:52.243
2019-05-09T06:38:52.243
3061
4010
24130
answer


「このようなアクセス」というのが `indirect reference`(間接参照)を意味するのであれば、bash でもできなくはないです。

[code]

    list1=(aa bb)
    list2=('cc      123' -n)
    
    for l in list1 list2
    do
      eval printf '%s\\n' \"\${$l[1]}\"
      eval printf '%s\\n' \"\${$l[0]}\"
    done
    
[/code]

`eval` を使うので `\\n` や `\"` としています。また、`echo` ではなく `printf` を使っているのは配列の要素に `-n` や
`-e` がある場合を考慮しているためです(`echo` のオプションとして処理されてしまいます)。


CC BY-SA 3.0
2016-04-19T02:36:43.483
24136
2016-04-19T02:36:43.483
24130
answer


シェル、bashの文法に関し、二つほど勘違いがあると思いますので、補足しておきます。

### 変数の参照

シェルにおいては殆どの場所で、変数名を書いても、それはだだ文字列としか見なされません。

[code]

    list1=(aa bb)
    list2=(cc dd)
    
    echo list1 list2
    # list1 list2 はただの文字列
    # 出力は 'list1 list2'
    
[/code]

これは`for`文の`in`の後もそうです。  
`for l in list1 list2;` とした時`l`は代入する変数名として扱われますが、`list1 list2`はただの文字列です。  
`l`という変数には`list1`と`list2`という文字列が順番に代入されます。  
`echo "$l"` としても、この文字列が出力されることになりますから`list1`などと表示されるだけです。

ですから、変数`l`に代入する前の段階で、変数`list1`と`list2`の値を参照し展開しておこう、というのがemasakaさんの回答です。  
出力する段階で、`l`に代入されている文字列を変数名として解釈させて、それの値を取り出そう、というのがargusさんの回答です。

### 配列変数の要素の参照

bashで配列の要素を参照するには `${list[0]}`のように`{}`で囲まなければいけません。  
シェルでは`[]`をパス名展開に使用するので、それと区別するためこれが必要になっています。

[code]

    list=(aa bb)
    
    echo $list[0]
    # $list は list の最初の要素（この場合 'aa'）に展開される。
    # それに '[0]' が付き、'aa[0]' になる。
    # この 'aa[0]' に対し、パス名展開が行なわれ、
    # 'aa'の後に'0'が有るファイル名に対しマッチが試みられる。
    # よって、出力は 'aa0' という名前のファイルが有れば、'aa0' 無ければ 'aa[0]'。
    
    echo "$list[0]"
    # ""でクオートされている
    # この場合 'aa[0]' になる所までは一緒だがパス名展開はされない。
    # 出力は 'aa[0]'。
    
    echo "${list[0]}"
    # {}を付けているので配列の要素への参照になる。
    # 出力は 'aa'。
    
[/code]


CC BY-SA 3.0
2016-04-19T03:09:08.393
24138
2016-04-19T03:09:08.393
3054
24130
answer


間接参照とすると、bashには間接参照として`${!var}`という方法があるのですが、`${!var[1]}`のようには使えないみたいですね。

というわけで、やや冗長ですが。

[code]

    list1=(aa bb)
    list2=(cc dd)
    
    for l in list1 list2
    do
      x=$l[0]
      echo ${!x}
      x=$l[1]
      echo ${!x}
    done
    
[/code]

あるいは、bash 4.3以降であれば、namerefを使って。

[code]

    list1=(aa bb)
    list2=(cc dd)
    
    for l in list1 list2
    do
      declare -n x=$l
      echo ${x[0]}
      echo ${x[1]}
    done
    
[/code]


CC BY-SA 3.0
2016-04-19T04:49:50.413
24142
2016-04-19T04:49:50.413
4010
24130
answer