35

このコードを機能させるにはどうすればよいですか?

#!/bin/bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
for FRUIT in ${!ARRAYNAME[@]}
do
    echo ${FRUIT}
done

このコード:

echo ${!ARRAYNAME[0]}

APPLEを印刷します。私は似たようなことをしようとしていますが、配列を反復処理するために「[@]」を使用しています。

前もって感謝します、

4

7 に答える 7

41

${!ARRAYNAME[@]}「のインデックス」を意味しますARRAYNAME。が設定されているのでbashのマニュアルページに記載されているようにARRAYNAME、配列ではなく文字列として、を返します0

これがを使用した解決策evalです。

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

eval array=\( \${${ARRAYNAME}[@]} \)

for fruit in "${array[@]}"; do
  echo ${fruit}
done

あなたが最初にやろうとしていたのは、間接参照を作成することでした。これらはbashバージョン2で導入されeval、シェルで反射のような動作を実現しようとするときの必要性を大幅に置き換えることを目的としていました。

配列で間接参照を使用するときに行う必要があるのは[@]、変数名の推測にを含めることです。

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

array="${ARRAYNAME}[@]"
for fruit in "${!array}"; do
  echo $fruit
done

とはいえ、この些細な例で間接参照を使用することは1つのことですが、Dennis Williamsonが提供するリンクに示されているように、実際のスクリプトで間接参照を使用することを躊躇する必要があります。これらは、コードを必要以上に混乱させることがほとんど保証されています。通常、連想配列で必要な機能を利用できます。

于 2012-06-24T20:07:16.443 に答える
20

これがevalなしでそれを行う方法です。

ここで説明されている Bashトリック#2を参照してください:http: //mywiki.wooledge.org/BashFAQ/006

bash3以降で動作するようです。

#!/bin/bash

ARRAYNAME='FRUITS'
tmp=$ARRAYNAME[@]
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
for FRUIT in "${!tmp}"
do
    echo "${FRUIT}"
done

関数を参照して配列を渡す方法を示す、より現実的な例を次に示します。

pretty_print_array () {
  local arrayname=$1
  local tmp=$arrayname[@]
  local array=( "${!tmp}" )
  local FS=', ' # Field seperator
  local var
  # Print each element enclosed in quotes and separated by $FS
  printf -v var "\"%s\"$FS" "${array[@]}"
  # Chop trailing $FS
  var=${var%$FS}
  echo "$arrayname=($var)"
}
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
pretty_print_array FRUITS
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT")
于 2014-09-17T00:56:13.190 に答える
7

evalたとえばコマンド置換が含まれている場合でも、配列要素を含むコードを実行します。また、配列要素内のbashメタ文字を解釈することによって配列要素を変更します。

これらの問題を回避するツールはdeclare リファレンスman bashです。declareの下を参照してください。

-n各名前にnameref属性を付けて、別の変数への名前参照にします。その他の変数は、nameの値によって定義されます。-n属性自体を使用または変更するものを除き、nameに対するすべての参照、割り当て、および属性の変更は、nameの値によって参照される変数に対して実行されます。nameref属性を配列変数に適用することはできません。

#!/bin/bash
declare -n ARRAYNAME='FRUITS'
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON")
for FRUIT in "${ARRAYNAME[@]}"
do
    echo "${FRUIT}"
done
于 2017-11-05T16:14:11.563 に答える
3

この答えは非常に遅くなりますが、これまでに提示されたものよりもはるかにクリーンなアプローチがあると思います(著者に敬意を表して)。

/ bash組み込みの-nオプションを使用することについてです。(詳細については、bashに入力してください)。declarelocalhelp declare

だからここに行きます:

ARRAYNAME='FRUITS';
FRUITS=(APPLE BANANA ORANGE);

# This is the critical addition. With help of option `-n` we declare
# variable `fruits` as indirect reference to another variable. Anytime
# we refer to ${fruits} we would actually refer to a variable whose
# name is stored in `fruits` variable:
declare -n fruits="${ARRAYNAME}";

# Here we use ${fruits} as ordinary variable, but in reality it refers
# to `FRUITS` variable:
for FRUIT in ${fruits[@]}; do
    echo "${FRUIT}";
done;

そして結果は次のとおりです。

APPLE
BANANA
ORANGE
于 2020-02-23T23:59:58.287 に答える
0

単純なOPの質問にもかかわらず、これらの回答は、最も一般的な実際のユースケース、つまり、ファイル名にまだ展開されていない空白またはワイルドカードを含む配列要素には対応しません。

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY=\(\${$ARRAYNAME[@]}\)

$ echo "${ARRAY[4]}"
broken
$ echo "${ARRAY[5]}"
config.h
$

これは機能します:

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY="(\"\${$ARRAYNAME[@]}\")"

$ echo "${ARRAY[3]}"
not broken
$ echo "${ARRAY[4]}"
*.h
$

"$@"notを使用する習慣を身に付ける必要があるのと同じように、ファイル名の拡張が必要な​​場合や、配列要素に空白が含まれる可能性がないことがわかっている場合を除き、配列の拡張に$@は常に内部を引用符で囲んでください。( )

これを行う:X=("${Y[@]}")

これではない:X=(${Y[@]})

于 2014-04-30T01:59:29.163 に答える
0

彼の質問に対する適切な方法と最良の答えは、実際の間接参照に関係していると思います。アスカーの元のコードへの変更は最小限で済み、連想配列を使用してこれを行うこともできます。

OP用に最小限に変更されたコード

declare -n ARRAYNAME='FRUITS'
declare -a FRUITS=( APPLE BANANA ORANGE )
for FRUIT in ${!ARRAYNAME[@]}
do
    echo "${ARRAYNAME[${FRUIT}]}"
done

出力

APPLE
BANANA
ORANGE

連想配列での使用法

declare -A associative_array
declare -n array_name=associative_array
associative_array[kittens]='cat'
associative_array[puppies]='dog'
associative_array[kitties]='cat'
associative_array[doggies]='dog'
for name in ${!array_name[@]} ; do 
echo $name has the value of "${associative_array[$name]}"
done

出力:

puppies has the value of dog
kittens has the value of cat
kitties has the value of cat
doggies has the value of dog

bashのmanページ全体を読む必要はなく、組み込みのhelp

$ help help
help: help [-dms] [pattern ...]
    Display information about builtin commands.
    
    Displays brief summaries of builtin commands.  If PATTERN is
    specified, gives detailed help on all commands matching PATTERN,
    otherwise the list of help topics is printed.
    
    Options:
      -d    output short description for each topic
      -m    display usage in pseudo-manpage format
      -s    output only a short usage synopsis for each topic matching
            PATTERN
    
    Arguments:
      PATTERN   Pattern specifying a help topic
    
    Exit Status:
    Returns success unless PATTERN is not found or an invalid option is given.

)。

使用法を宣言する:

declare: declare [-aAfFgilnrtux] [-p] [name[=value] ...]
    Set variable values and attributes.
    
    Declare variables and give them attributes.  If no NAMEs are given,
    display the attributes and values of all variables.
    
    Options:
      -f    restrict action or display to function names and definitions
      -F    restrict display to function names only (plus line number and
            source file when debugging)
      -g    create global variables when used in a shell function; otherwise
            ignored
      -p    display the attributes and value of each NAME
    
    Options which set attributes:
      -a    to make NAMEs indexed arrays (if supported)
      -A    to make NAMEs associative arrays (if supported)
      -i    to make NAMEs have the `integer' attribute
      -l    to convert the value of each NAME to lower case on assignment
      -n    make NAME a reference to the variable named by its value
      -r    to make NAMEs readonly
      -t    to make NAMEs have the `trace' attribute
      -u    to convert the value of each NAME to upper case on assignment
      -x    to make NAMEs export
    
    Using `+' instead of `-' turns off the given attribute.
    
    Variables with the integer attribute have arithmetic evaluation (see
    the `let' command) performed when the variable is assigned a value.
    
    When used in a function, `declare' makes NAMEs local, as with the `local'
    command.  The `-g' option suppresses this behavior.
    
    Exit Status:
    Returns success unless an invalid option is supplied or a variable
    assignment error occurs.
于 2021-12-14T19:10:54.490 に答える
-1

別の便利なユースケースを追加したかっただけです。私は別の、しかし関連する問題の解決策をウェブで探していました

ARRAYNAME=( FRUITS VEG )
FRUITS=( APPLE BANANA ORANGE )
VEG=( CARROT CELERY CUCUMBER )
for I in "${ARRAYNAME[@]}"
do
    array="${I}[@]"
    for fruit in "${!array}"; do
        echo $fruit
    done
done
于 2013-11-08T05:12:48.007 に答える