Değişken, bir dizi adının parçası olarak nasıl kullanılır?


11

İki dizim var:

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

ve bunlardan birini komut satırı argümanı kullanarak yazdırmak istiyorum, yani herhangi bir şey olmadan if else.

Sentaks üzerinde birkaç varyasyon denemedim. Ben böyle bir şey yapmak istiyorum:

ARG="$1"

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

ancak "kötü değiştirme" hatası alıyorum. Bunu nasıl başarabilirim?


Bu kesin olarak deyimsel bash değildir . Lütfen bunu yapma.
Wildcard

Yanıtlar:


22

Bunu yapmayı deneyin:

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

NOT

  • from man bash(parametre genişletme):
    ${parameter}
           The value of parameter is substituted.
 The braces are required when parameter is a positional parameter with
  more than one

veya parametrenin ardından adının bir parçası olarak yorumlanmayacak bir karakter gelir.
* Parametrenin ilk karakteri bir ünlem işareti (!) İse, değişken dolaylılık düzeyi eklenir. Bash, değişkenin adı olarak parametrenin geri kalanından oluşan değişkenin değerini kullanır; bu değişken daha sonra genişletilir ve bu değer, değiştirmenin geri kalanında, parametrenin kendisinden ziyade kullanılır. Buna dolaylı genişleme denir. * Bunun istisnaları, aşağıda açıklanan $ {! Öneki *} ve $ {! Name [@]} genişletmeleridir. Ünlem işareti dolaylı tanıtmak için hemen sol küme ayracı takip etmelidir.


Değişkenin !önünde tam olarak ne var var? Bu nasıl çalışıyor, Google'da tarihin yerini almış gibi görünüyordu, ancak bunun nasıl çalıştığını göremedim.
Aaron

Düzenlenen yayınımı gör
Gilles Quenot

4

Dolaylı erişimi başka bir yanıtta işaret edildiği gibi kullanabilmenize rağmen , başka bir yol (ksh ve Bash 4.3 ve daha yeni sürümlerde) aderefs kullanmak olacaktır. Özellikle diziler söz konusu olduğunda, diziyi aderef üzerinden dizine ekleyebileceğiniz ve dizini başvuru olarak kullanılan değişkene koymanız gerekmediği için bu daha yararlı olabilir.

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

Bu dolaylı erişim yoluyla çalışmaz:

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

Bir C programcının koyabileceği gibi, ${!q[1]}burada qbir diziye işaretçi olmak yerine bir işaretçi dizisi gibi davranır .



1
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

not: boşluk durumunda kaçış !

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

1

Bu çok fazla deneme yanılma aldı ancak sonunda işe yaradı.

Youness'ten biraz ilham aldım. Ama diğer tüm cevaplar benim eski bash yardımcı olmadı (suse11sp1 [3.2.51 (1) -çalışma])

'For' döngüsü dolaylı diziyi genişletmeyi reddetti, bunun yerine önceden genişletmeniz gerekiyor, bunu yeni değişken adınızla başka bir dizi oluşturmak için kullanın. Aşağıdaki örneğim, amaçladığım kullanım olduğu için bir çift döngü gösteriyor.

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

Ben ilk dizi girişinden "New_" silmek, sonra "FOOthings" almak için "şeyler" ile birleştirmek için # kullanıyorum. yankı ve eval ile \ $ {}, sonra yeni bir $ () sarılmış ve yeni değişken adı atanan hata atmadan sırayla şeylerini yapmak.

$ 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
GÜNCELLEME ##### 2018/06/07

Geçenlerde bu konuda bir spin daha keşfettim. Oluşturulan değişken aslında bir dizi değil, boşlukla ayrılmış bir dizedir. Yukarıdaki görev için bu tamam, çünkü "için" nasıl çalışır, dizi okumuyor, genişletilir ve sonra döngü, aşağıdaki özü bakın:

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

Ama sonra bir dizi olarak kullanmak gerekiyordu. Bunun için bir adım daha atmam gerekiyordu. Dennis Williamson tarafından kod kelimesini kelimesine aldım . Test ettim ve iyi çalışıyor.

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

"IFS = ','", sınırlayıcınızı içeren bir değişkendir. "read" ile "read", sokmayı dizi değişkenine geri keser ve besler. Bu tırnak işaretleri için bir saygı vardır, ancak bunu yönetmek için okuma birkaç seçenek vardır , örneğin ben ihtiyacım olmayan -r bayrağı kaldırdım. Şimdi bu eklemeyi, verilerin olması gerektiği gibi ele alınmasını ve ele alınmasını sağlayan değişken oluşturmada birleştirdim.

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

0

Dinamik olarak adlandırılmış bir değişken bu şekilde oluşturulur (bash sürümü <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[@]}

Aşağıda, dinamik olarak adlandırılmış dizileri yönetmek için kullanılabilen bir grup işlev bulunmaktadır (bash sürümü <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

Aşağıda, dinamik olarak adlandırılmış dizileri yönetmek için kullanılabilen bir grup işlev bulunmaktadır (bash sürümü> = 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

Bu örnekler hakkında daha fazla bilgi için Ludvik Jerabek'ten Dinamik Dizilerle Bashed'i ziyaret edin


1
Bunun neden reddedildiğini merak ediyorum. Yaklaşımda yanlış / tehlikeli bir şey var mı? Bash <4.3 işlevlerini kullanmak ister.
stephenmm

Yayınınızı takdir ediyorum, yararlı bilgiler ve özel olarak "Öğe sayısını al" talimatı buldum: eval echo \ $ {# $ my_variable_name [@]}
Daniel Perez

-1

olmaz :(

dizileriniz bu kadar basitse ilişkilendirilebilir diziler kullanın

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

ne yazık ki, dizileriniz daha karmaşıksa (örneğin array=( "a b" c )), bu işe yaramaz. Ardından, hedefinize ulaşmak için başka bir yol hakkında daha fazla düşünmeniz gerekir.


Downvote'un nedeni nedir? İlişkilendirilebilir dizi, öğelerimin hepsinde boşluk olmayacağını varsayarak, her şeyi gruplandırmak için güzel bir yol sağlar.
Aaron

2
@Aaron Öğeleriniz boşluk içermediğini varsayarsak, bu makul bir tasarımdır. @Waelel Sorunuzun ana odağı açıkça mümkün olduğunda cevaba “hiçbir şekilde” başlamakla başlamak, iyi bir fikir değildi.
Gilles 'SO- kötü olmayı kes'

-1

kullanım 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.