두 개의 배열이 있습니다.
arrayA=(1 2 3)
arrayB=(a b c)
명령줄 인수를 사용하여 그 중 하나를 인쇄하고 싶습니다. 즉, if else
.
성공하지 못한 채 몇 가지 구문 변형을 시도했습니다. 나는 이런 일을하고 싶다 :
ARG="$1"
echo ${array${ARG}[@]}
하지만 "잘못된 대체" 오류가 발생합니다. 이 목표를 어떻게 달성할 수 있나요?
답변1
이 시도:
$ 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
숫자 또는 인수 뒤에 이름의 일부로 해석되지 않는 문자가 오는 경우.
* 매개변수의 첫 번째 문자가 느낌표(!)인 경우 1단계 변수 간접 주소 지정이 도입됩니다. Bash는 나머지 인수로 구성된 변수 값을 변수 이름으로 사용합니다. 그런 다음 해당 변수를 확장하고 인수 자체의 값이 아닌 나머지 대체에 해당 값을 사용합니다. 이를 간접 확장이라고 합니다. * 아래 설명된 ${!prefix*} 및 ${!name[@]}에 대한 확장은 예외입니다. 느낌표는 간접적인 관계를 소개하기 위해 여는 중괄호 바로 뒤에 와야 합니다.
답변2
지적한 대로 간접 액세스를 사용할 수도 있지만또 다른 대답, 또 다른 접근 방식(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
답변3
많은 시행착오를 겪었지만 결국 성공했습니다.
유네스에게서 영감을 얻었어요. 그러나 다른 모든 답변은 이전 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
그러나 그런 다음 이를 배열로 사용해야 합니다. 그러기 위해서는 한 단계 더 나아가야 합니다. 코드를 그대로 기록했습니다.데니스 윌리엄슨. 테스트 해봤는데 잘 작동합니다.
IFS=', ' read -r -a TheNewVariable <<< ${TheNewVariable[@]}
"IFS=', '"는 구분 기호를 포함하는 변수입니다. "read" 및 "-a"는 문자열을 잘라내어 배열 변수로 반환합니다. 인용문은 고려되지 않지만 몇 가지 옵션이 있습니다.읽다예를 들어 이를 관리하기 위해 필요하지 않은 -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
답변4
동적으로 명명된 변수를 생성하는 방법입니다(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의 동적 배열 공격