簡體   English   中英

如何將關聯數組作為參數傳遞給 Bash 中的 function?

[英]How to pass an associative array as argument to a function in Bash?

如何將關聯數組作為參數傳遞給 function? 這在 Bash 中是否可行?

下面的代碼沒有按預期工作:

function iterateArray
{
    local ADATA="${@}"            # associative array

for key in "${!ADATA[@]}"
do
    echo "key - ${key}"
    echo "value: ${ADATA[$key]}"

done

}

像普通的 arrays 一樣將關聯的 arrays 傳遞給 function 不起作用:

iterateArray "$A_DATA"

或者

iterateArray "$A_DATA[@]"

上周我遇到了完全相同的問題,並考慮了很長時間。

似乎關聯數組無法序列化或復制。 關聯數組有一個很好的Bash FAQ條目,其中詳細解釋了它們 最后一部分為我提供了以下對我有用的想法:

function print_array {
    # eval string into a new associative array
    eval "declare -A func_assoc_array="${1#*=}
    # proof that array was successfully created
    declare -p func_assoc_array
}

# declare an associative array
declare -A assoc_array=(["key1"]="value1" ["key2"]="value2")
# show associative array definition
declare -p assoc_array

# pass associative array in string form to function
print_array "$(declare -p assoc_array)" 

基於Florian Feldhaus的解決方案:

# Bash 4+ only
function printAssocArray # ( assocArrayName ) 
{
    var=$(declare -p "$1")
    eval "declare -A _arr="${var#*=}
    for k in "${!_arr[@]}"; do
        echo "$k: ${_arr[$k]}"
    done

}

declare -A conf
conf[pou]=789
conf[mail]="ab\npo"
conf[doo]=456

printAssocArray "conf" 

輸出將是:

doo: 456
pou: 789
mail: ab\npo

更新,以完全回答問題,這是我庫中的一小部分:

通過引用迭代關聯數組

shopt -s expand_aliases
alias array.getbyref='e="$( declare -p ${1} )"; eval "declare -A E=${e#*=}"'
alias array.foreach='array.keys ${1}; for key in "${KEYS[@]}"'

function array.print {
    array.getbyref
    array.foreach
    do
        echo "$key: ${E[$key]}"
    done
}

function array.keys {
    array.getbyref
    KEYS=(${!E[@]})
}   

# Example usage:
declare -A A=([one]=1 [two]=2 [three]=3)
array.print A

這是我之前工作的發展,我將在下面進行介紹。

@ffeldhaus-很好的響應,我接受了它並運行了它:

t() 
{
    e="$( declare -p $1 )"
    eval "declare -A E=${e#*=}"
    declare -p E
}

declare -A A='([a]="1" [b]="2" [c]="3" )'
echo -n original declaration:; declare -p A
echo -n running function tst: 
t A

# Output:
# original declaration:declare -A A='([a]="1" [b]="2" [c]="3" )'
# running function tst:declare -A E='([a]="1" [b]="2" [c]="3" )'

如果您使用的是Bash 4.3或更高版本, 最干凈的方法是按名稱傳遞關聯數組,然后使用帶有local -n的名稱引用在函數內部訪問它。 例如:

function foo {
    local -n data_ref=$1
    echo ${data_ref[a]} ${data_ref[b]}
}

declare -A data
data[a]="Fred Flintstone"
data[b]="Barney Rubble"
foo data

您不必使用_ref后綴; 這就是我在這里選擇的 只要引用與原始變量名稱不同即可,您可以調用該引用(否則將收到“循環名稱引用”錯誤)。

您只能按名稱傳遞關聯數組。

更好地(更有效)按名稱傳遞常規數組。

喲:

 #!/bin/bash
   declare -A dict

   dict=(
    [ke]="va"
    [ys]="lu"
    [ye]="es" 
   )

   fun() {
     for i in $@; do
       echo $i
     done
    }

   fun ${dict[@]} # || ${dict[key]} || ${!dict[@] || ${dict[$1]} 

Z

這是另一種方法:您可以在將關聯數組傳遞給 function 時手動序列化它,然后將其反序列化回 function 內的新關聯數組:

1. 關聯數組的手動傳遞(通過序列化/反序列化)

這是來自我的eRCaGuy_hello_world 存儲庫的完整、可運行的示例:

array_pass_as_bash_parameter_2_associative.sh

# Print an associative array using manual serialization/deserialization
# Usage:
#       # General form:
#       print_associative_array array_length array_keys array_values
#
#       # Example:
#       #                          length        indices (keys)    values
#       print_associative_array "${#array1[@]}" "${!array1[@]}" "${array1[@]}"
print_associative_array() {
    i=1

    # read 1st argument, the array length
    array_len="${@:$i:1}"
    ((i++))

    # read all key:value pairs into a new associative array
    declare -A array
    for (( i_key="$i"; i_key<$(($i + "$array_len")); i_key++ )); do
        i_value=$(($i_key + $array_len))
        key="${@:$i_key:1}"
        value="${@:$i_value:1}"
        array["$key"]="$value"
    done

    # print the array by iterating through all of the keys now
    for key in "${!array[@]}"; do
        value="${array["$key"]}"
        echo "  $key: $value"
    done
}

# Let's create and load up an associative array and print it
declare -A array1
array1["a"]="cat"
array1["b"]="dog"
array1["c"]="mouse"

#                         length         indices (keys)    values
print_associative_array "${#array1[@]}" "${!array1[@]}" "${array1[@]}"

樣品 output:

  a: cat
  b: dog
  c: mouse

解釋:

對於名為print_associative_array的給定 function ,以下是一般形式:

# general form
print_associative_array array_length array_keys array_values

對於名為array1的數組,以下是如何獲取數組長度、索引(鍵)和值:

  1. 數組長度: "${#array1[@]}"
  2. 所有數組索引(在本例中為鍵,因為它是關聯數組): "${!array1[@]}"
  3. 所有數組值: "${array1[@]}"

因此,對print_associative_array的示例調用如下所示:

# example call
#                         length         indices (keys)    values
print_associative_array "${#array1[@]}" "${!array1[@]}" "${array1[@]}"

將數組的長度放在首位是必不可少的,因為它允許我們在傳入的序列化數組到達print_associative_array function 時解析所有傳入 arguments 的魔術@數組中的數組。

要解析@數組,我們將使用數組切片,其描述如下(此片段是從我的答案復制粘貼在這里):

# array slicing basic format 1: grab a certain length starting at a certain
# index
echo "${@:2:5}"
#         │ │
#         │ └────> slice length
#         └──────> slice starting index (zero-based)

2. [比上面更好的技術!] 通過引用傳遞數組

...正如@Todd Lehman 在他的回答中解釋的那樣

# Print an associative array by passing the array by reference
# Usage:
#       # General form:
#       print_associative_array2 array
#       # Example
#       print_associative_array2 array1
print_associative_array2() {
    # declare a local **reference variable** (hence `-n`) named `array_reference`
    # which is a reference to the value stored in the first parameter
    # passed in
    local -n array_reference="$1"

    # print the array by iterating through all of the keys now
    for key in "${!array_reference[@]}"; do
        value="${array_reference["$key"]}"
        echo "  $key: $value"
    done
}

echo 'print_associative_array2 array1'
print_associative_array2 array1
echo ""
echo "OR (same thing--quotes don't matter in this case):"
echo 'print_associative_array2 "array1"'
print_associative_array2 "array1"

樣品 output:

print_associative_array2 array1
  a: cat
  b: dog
  c: mouse

OR (same thing--quotes don't matter in this case):
print_associative_array2 "array1"
  a: cat
  b: dog
  c: mouse

也可以看看:

  1. [my answer] a more-extensive demo of me serializing/deserializing a regular "indexed" bash array in order to pass one or more of them as parameters to a function: Passing arrays as parameters in bash
  2. [我的回答]我通過引用傳遞常規“索引”bash 數組的演示: Passing arrays as parameters in bash
  3. [我的答案] 數組切片: Unix & Linux:Bash:位置參數切片
  4. [我的問題]為什么man bash pages state 的declarelocal -n屬性“不能應用於數組變量”,但它可以?

這是我今天使用eval echo ...進行間接處理的一種解決方案:

print_assoc_array() {
    local arr_keys="\${!$1[@]}" # \$ means we only substitute the $1
    local arr_val="\${$1[\"\$k\"]}"
    for k in $(eval echo $arr_keys); do #use eval echo to do the next substitution
        printf "%s: %s\n" "$k" "$(eval echo $arr_val)"
    done
}

declare -A my_arr
my_arr[abc]="123"
my_arr[def]="456"
print_assoc_array my_arr

在bash 4.3上的輸出:

def: 456
abc: 123

從有史以來最好的Bash指南中:

declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
    echo "User: $user, full name: ${fullNames[$user]}."
done

我認為您遇到的問題是$@ 不是關聯數組 :“ @:擴展為所有位置參數的所有單詞。如果用雙引號將其擴展為所有位置參數的列表作為單個單詞。”

出色的。 @Todd Lehman描述的簡單解決方案解決了我的關聯數組傳遞問題。 我必須將 3 個參數,一個 integer、一個關聯數組和一個索引數組傳遞給 function。

前段時間我讀到,由於 bash 中的 arrays 不是一流實體, 因此 arrays 無法作為 ZDBC11C1554E1B671D71D9CZ 傳遞給函數 Z77769 函數 顯然,這畢竟不是全部真相 我剛剛實現了一個解決方案,其中 function 處理這些參數,就像這樣......

function serve_quiz_question() {
    local index="$1"; shift
    local -n answers_ref=$1; shift
    local questions=( "$@" )

    current_question="${questions[$index]}"
    echo "current_question: $current_question"
    #...
    current_answer="${answers_ref[$current_question]}"
    echo "current_answer: $current_answer"
}

declare -A answers 
answers[braveheart]="scotland"
answers[mr robot]="new york"
answers[tron]="vancouver"
answers[devs]="california"

# integers would actually be assigned to index \
# by iterating over a random sequence, not shown here.
index=2
declare -a questions=( "braveheart" "devs" "mr robot" "tron"  )

serve_quiz_question "$index" answers "${questions[@]}"  

隨着局部變量的分配,我不得不shift位置參數移開,以便以( "$@" )將剩下的內容分配給索引問題數組。

需要索引數組,以便我們可以可靠地迭代所有問題,無論是隨機還是有序序列。 關聯 arrays 不是有序數據結構,因此不適用於任何類型的可預測迭代。

Output:

current_question: mr robot
current_answer: new york

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM