[unix] 배열 이름의 일부로 변수를 사용하는 방법

두 개의 배열이 있습니다.

arrayA=(1 2 3)
arrayB=(a b c)

그리고 명령 줄 인수를 사용하여 그중 하나를 인쇄하고 싶습니다 if else.

나는 성공하지 않고 구문에 대해 몇 가지 변형을 시도했다. 나는 이런 식으로하고 싶다 :

ARG="$1"

echo ${array${ARG}[@]}

그러나 “나쁜 대체”오류가 발생합니다. 어떻게하면 되나요?



답변

이것을 시도하십시오 :

$ arrayA=(1 2 3)
$ x=A
$ var=array$x[@]
$ echo ${!var}
1 2 3

노트

  • man bash(파라미터 확장)
    ${parameter}
           The value of parameter is substituted.
 The braces are required when parameter is a positional parameter with
  more than one

숫자 또는 매개 변수 뒤에 이름의 일부로 해석되지 않는 문자가 오는 경우.
* 매개 변수의 첫 문자가 느낌표 (!) 인 경우 가변 간접 레벨이 도입됩니다. Bash는 나머지 매개 변수에서 형성된 변수의 값을 변수의 이름으로 사용합니다. 그런 다음이 변수가 확장되고 해당 값은 매개 변수 자체의 값이 아닌 나머지 대체에 사용됩니다. 이것을 간접 확장이라고합니다. * 이에 대한 예외는 아래 설명 된 $ {! prefix *} 및 $ {! name [@]}의 확장입니다. 느낌표는 간접적으로 도입하기 위해 즉시 왼쪽 괄호를 따라야합니다.


답변

다른 답변 에서 지적한 것처럼 간접 액세스를 사용할 수 있지만 ksh 및 Bash 4.3 이상에서 다른 방법은 nameref를 사용하는 것입니다. 특히 배열의 경우 nameref를 통해 배열을 색인 할 수 있고 참조로 사용되는 변수에 색인을 넣을 필요가 없으므로 더 유용 할 수 있습니다.

arr1=(a b c)
arr2=(x y z)
typeset -n p=arr1    # or 'declare -n' 
echo "${p[1]}"       # prints 'b'

간접 액세스를 통해 작동하지 않습니다.

q=arr2
echo "${!q}"         # prints 'x', the same as $arr2
echo "${!q[1]}"      # doesn't work, it tries to take q[1] as a reference

C 프로그래머가 말했듯이 ${!q[1]}여기 q에서는 배열에 대한 포인터가 아닌 포인터의 배열 인 것처럼 작동 합니다.


답변

arrayA=(1 2 3)
arrayB=(a b c)

ARG="$1"

eval echo \${array${ARG}[@]}

dataget (){ 
    eval echo \${array${1}[${2:-@}]}
}
$ dataget A
1 2 3
$ dataget A 0
1
$ dataget B 1
b

참고 :
공간이 부족한 경우 탈출 하십시오 !

eval dostuff \"\${array${1}[${2:-@}]}\"


답변

이것은 많은 시행 착오를 겪었지만 결국 효과가있었습니다.

유스에서 영감을 얻었습니다. 그러나 다른 모든 대답은 이전 bash에 도움이되지 않았습니다 (suse11sp1 [3.2.51 (1) -release])

‘for’루프는 간접 배열 확장을 거부했습니다. 대신 사전 확장해야합니다.이를 사용하여 새 변수 이름으로 다른 배열을 만듭니다. 아래의 예는 의도 한 용도이므로 이중 루프를 보여줍니다.

THEBIGLOOP=(New_FOO New_BAR)

FOOthings=(1 2 3)
BARthings=(a b c)

for j in ${THEBIGLOOP[*]}
do
    TheNewVariable=$(eval echo \${${j#New_}things[@]})

    for i in $TheNewVariable
        do
            echo  $j $i" hello"
        echo
    done
done

#을 사용하여 첫 번째 배열 항목에서 “New_”를 삭제 한 다음 “things”와 연결하여 “FOOthings”를 얻습니다. echo 및 eval을 사용하여 \ $ {}을 입력 한 다음, 오류를 발생시키지 않고 순서대로 수행합니다. 새 $ ()로 싸서 새 변수 이름이 지정되었습니다.

$ Test.sh

New_FOO 1 hello

New_FOO 2 hello

New_FOO 3 hello

New_BAR a hello

New_BAR b hello

New_BAR c hello

업데이트 ##### 2018/06/07

최근 에이 문제에 대한 또 다른 스핀을 발견했습니다. 생성 된 변수는 실제로 배열이 아니라 공백으로 구분 된 문자열입니다. 위의 작업은 “for”의 작동 방식으로 인해 배열이 읽히지 않고 확장 된 다음 반복됩니다. 아래 추출을 참조하십시오.

for VARIABLE in 1 2 3 4 5 .. N
do
    command1
    command2
    commandN
done

그러나 그런 다음 배열로 사용해야했습니다. 이를 위해 한 단계 더 수행해야했습니다. Dennis Williamson이 작성한 코드를 그대로 사용했습니다 . 나는 그것을 테스트했고 잘 작동합니다.

IFS=', ' read -r -a TheNewVariable <<< ${TheNewVariable[@]}

“IFS = ‘,'”는 델리 미네 이터가 포함 된 변수입니다. “-a”와 함께 “read”는 찌르기를 자르고 배열 변수로 다시 보냅니다. 참고이 따옴표에 대한 존중이없는,하지만 몇 가지 옵션이 있습니다 읽기 이 관리는, 예를 들어 나는 것은 내가 필요하지 않았다 -r 플래그를 제거했습니다. 이제 변수 생성에이 추가 기능을 결합하여 데이터를 원하는대로 처리하고 처리 할 수 ​​있습니다.

THEBIGLOOP=(New_FOO New_BAR)

FOOthings=(1 2 3)
BARthings=(a b c)

for j in ${THEBIGLOOP[*]}
do

    IFS=', ' read -a TheNewVariable <<< $(eval echo \${${j#New_}things[@]})

    for i in ${TheNewVariable[@]}  #Now have to wrap with {} and expand with @
        do
            echo  $j $i" hello"
            echo  ${TheNewVariable[$i]}  #This would not work in the original code
        echo
    done
done


답변

이것이 동적으로 명명 된 변수를 만드는 방법입니다 (bash 버전 <4.3).

# Dynamically named array
my_variable_name="dyn_arr_names"
eval $my_variable_name=\(\)

# Adding by index to the array eg. dyn_arr_names[0]="bob"
eval $my_variable_name[0]="bob"

# Adding by pushing onto the array eg. dyn_arr_names+=(robert)
eval $my_variable_name+=\(robert\)

# Print value stored at index indirect
echo ${!my_variable_name[0]}

# Print value stored at index
eval echo \${$my_variable_name[0]}

# Get item count
eval echo \${#$my_variable_name[@]}

다음은 동적으로 명명 된 배열을 관리하는 데 사용할 수있는 함수 그룹입니다 (bash 버전 <4.3).

# Dynamically create an array by name
function arr() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
     # The following line can be replaced with 'declare -ag $1=\(\)'
     # Note: For some reason when using 'declare -ag $1' without the parentheses will make 'declare -p' fail
    eval $1=\(\)
}

# Insert incrementing by incrementing index eg. array+=(data)
function arr_insert() { 
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval $1[\$\(\(\${#${1}[@]}\)\)]=\$2
}

# Update an index by position
function arr_set() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval ${1}[${2}]=\${3}
}

# Get the array content ${array[@]}
function arr_get() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval echo \${${1}[@]}
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_at() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; }
    local v=$1
    local i=$2
    local max=$(eval echo \${\#${1}[@]})
    # Array has items and index is in range
    if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]]
    then 
        eval echo \${$v[$i]}
    fi
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_count() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    local v=${1}
    eval echo \${\#${1}[@]}
}



array_names=(bob jane dick)

for name in "${array_names[@]}"
do
    arr dyn_$name
done

echo "Arrays Created"
declare -a | grep "a dyn_"

# Insert three items per array
for name in "${array_names[@]}"
do
    echo "Inserting dyn_$name abc"
    arr_insert dyn_$name "abc"
    echo "Inserting dyn_$name def"
    arr_insert dyn_$name "def"
    echo "Inserting dyn_$name ghi"
    arr_insert dyn_$name "ghi"
done

for name in "${array_names[@]}"
do
    echo "Setting dyn_$name[0]=first"
    arr_set dyn_$name 0 "first"
    echo "Setting dyn_$name[2]=third"
    arr_set dyn_$name 2 "third"
done 

declare -a | grep "a dyn_"

for name in "${array_names[@]}"
do
    arr_get dyn_$name
done


for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name by index"
    # Print by index
    for (( i=0 ; i < $(arr_count dyn_$name) ; i++ ))
    do
        echo "dyn_$name[$i]: $(arr_at dyn_$name $i)"

    done
done

for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name"
    for n in $(arr_get dyn_$name)
    do
        echo $n
    done
done

다음은 동적으로 명명 된 배열을 관리하는 데 사용할 수있는 함수 그룹입니다 (bash 버전> = 4.3).

# Dynamically create an array by name
function arr() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -g -a $1=\(\)   
}

# Insert incrementing by incrementing index eg. array+=(data)
function arr_insert() { 
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1
    r[${#r[@]}]=$2
}

# Update an index by position
function arr_set() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1 
    r[$2]=$3
}

# Get the array content ${array[@]}
function arr_get() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1 
    echo ${r[@]}
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_at() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; }
    declare -n r=$1 
    local max=${#r[@]}
    # Array has items and index is in range
    if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]]
    then 
        echo ${r[$2]}
    fi
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_count() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1
    echo ${#r[@]}
}



array_names=(bob jane dick)

for name in "${array_names[@]}"
do
    arr dyn_$name
done

echo "Arrays Created"
declare -a | grep "a dyn_"

# Insert three items per array
for name in "${array_names[@]}"
do
    echo "Inserting dyn_$name abc"
    arr_insert dyn_$name "abc"
    echo "Inserting dyn_$name def"
    arr_insert dyn_$name "def"
    echo "Inserting dyn_$name ghi"
    arr_insert dyn_$name "ghi"
done

for name in "${array_names[@]}"
do
    echo "Setting dyn_$name[0]=first"
    arr_set dyn_$name 0 "first"
    echo "Setting dyn_$name[2]=third"
    arr_set dyn_$name 2 "third"
done 

declare -a | grep 'a dyn_'

for name in "${array_names[@]}"
do
    arr_get dyn_$name
done


for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name by index"
    # Print by index
    for (( i=0 ; i < $(arr_count dyn_$name) ; i++ ))
    do
        echo "dyn_$name[$i]: $(arr_at dyn_$name $i)"

    done
done

for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name"
    for n in $(arr_get dyn_$name)
    do
        echo $n
    done
done

이 예제에 대한 자세한 내용은 Ludvik Jerabek의 동적 배열에 의한 배싱하기 를 참조하십시오.


답변

절대 안돼 🙁

배열이 그렇게 단순하면 연관 배열을 사용하십시오.

    declare -A array
    array[A]="1 2 3"
    array[B]="a b c"

불행히도 배열이 더 복잡한 경우 (예 🙂 array=( "a b" c )작동하지 않습니다. 그런 다음 목표에 도달하는 다른 방법에 대해 더 열심히 생각해야합니다.


답변

사용하다 eval

arrayA=(1 2 3)
ARG=arrayA
eval echo \${$ARG[@]} # equivalent to eval echo \${arrayA[@]}
                      # note that we escape the first '$' to prevent from 
                      # its parameter expansion before passing it to echo