如何在shell中从函数返回关联数组?

68bkxrlz  于 2023-03-03  发布在  Shell
关注(0)|答案(3)|浏览(194)
process_ls_entry() {
    IFS=' ' read -r -a array <<< "$1"
    declare -A LS_MAP
    LS_MAP[entry]="${array[@]::1}"
    LS_MAP[mode]="${array[@]:1:1}"
    LS_MAP[size]="${array[@]:2:1}"
    LS_MAP[num_blocks]="${array[@]:3:1}"
    timestamp="${array[@]:4}"
    timestamp=${timestamp// /_}
    LS_MAP[timestamp]="${timestamp}"
    # how to return?
}

a="temp_dir drwxr-xr-x 0 0 Fri Jul 13 07:08:00 2012"
output=( $(process_ls_entry "$a") )

# entry -> temp_dir
# mode -> drwxr-xr-x
# size -> 0
# size -> 0
# timestamp -> Fri_Jul_13_07:08:00_2012

echo ${output[timestamp]}

我创建了一个函数
如何在shell脚本中正确地从函数返回关联数组?

tvz2xvvm

tvz2xvvm1#

使用可怕的eval(如果您可以信任process_ls_entry()的输出),您可以执行以下操作:

process_ls_entry() {
    IFS=' ' read -r -a array <<< "$1"
    declare -A LS_MAP
    LS_MAP[entry]="${array[@]::1}"
    LS_MAP[mode]="${array[@]:1:1}"
    LS_MAP[size]="${array[@]:2:1}"
    LS_MAP[num_blocks]="${array[@]:3:1}"
    timestamp="${array[@]:4}"
    timestamp=${timestamp// /_}
    LS_MAP[timestamp]="${timestamp}"
    # dump LS_MAP in shell reusable format
    declare -p LS_MAP
}

那么就叫它:

a="temp_dir drwxr-xr-x 0 0 Fri Jul 13 07:08:00 2012"
tmp=$(process_ls_entry "$a")

# use eval to declare same array with a different name output
eval "${tmp/LS_MAP=/output=}"

echo "${output[timestamp]}"

输出:

Fri_Jul_13_07:08:00_2012
hmae6n7t

hmae6n7t2#

这里有一个选项,似乎做的伎俩。

process_ls_entry() {
    read -r -a array <<< "$1"

    local timestamp="${array[4]}"
    timestamp=${timestamp// /_}

    # Print the right hand side of an associative array expression.
    # This will allow the caller to assign it to a variable name
    # of their choosing.
    printf '(
      [entry]=%q
      [mode]=%q
      [size]=%q
      [num_blocks]=%q
      [timestamp]=%q
    )' "${array[@]::4}" "$timestamp"
}

print_ls_map() {
    local -n ls_map=$1
    echo "The keys of LS_MAP are ${!ls_map[@]}"
    echo "The values of LS_MAP are ${ls_map[@]}"
}

a="temp_dir drwxr-xr-x 0 0 Fri Jul 13 07:08:00 2012"

# -r = readonly
declare -rA LS_MAP=$(process_ls_entry "$a")

# And you can even 'pass' the array to a function using
# named references
# output:
#     The keys of LS_MAP are mode size timestamp num_blocks entry
#     The values of LS_MAP are drwxr-xr-x 0 Fri_Jul_13_07:08:00_2012 0 temp_dir
print_ls_map LS_MAP
n9vozmp4

n9vozmp43#

您可以通过返回字符串形式的关联数组,然后将该字符串分配给调用上下文中的新关联数组来完成此操作。

process_ls_entry() {
    IFS=' ' read -r -a array <<< "$1"
    declare -A LS_MAP
    LS_MAP[entry]="${array[@]::1}"
    LS_MAP[mode]="${array[@]:1:1}"
    LS_MAP[size]="${array[@]:2:1}"
    LS_MAP[num_blocks]="${array[@]:3:1}"
    timestamp="${array[@]:4}"
    timestamp=${timestamp// /_}
    LS_MAP[timestamp]="${timestamp}"
    echo "${LS_MAP[@]@K}" # Expand associative array as string.
}

a="temp_dir drwxr-xr-x 0 0 Fri Jul 13 07:08:00 2012"
# Call function and assign output string to new associative array.
declare -A output="($(process_ls_entry "$a"))"
for key in "${!output[@]}"; do
    echo "output[${key}]=${output[${key}]}"
done

输出:

output[mode]=drwxr-xr-x
output[entry]=temp_dir
output[num_blocks]=0
output[timestamp]=Fri_Jul_13_07:08:00_2012
output[size]=0

在Bash中,可以为关联数组分配一个字符串,该字符串只包含一个交替键和值的列表。
当赋值给关联数组时,复合赋值中的单词可以是需要下标的赋值语句,也可以是解释为交替键和值序列的单词列表:名称=(键1值1键2值2 ...). https://www.gnu.org/software/bash/manual/html_node/Arrays.html
可以使用@K参数扩展运算符将关联数组扩展为该形式。
${参数@运算符}
展开是参数值的变换或参数本身的信息,取决于运算符的值。每个运算符是一个字母:
K:生成一个可能带引号的parameter值版本,但它将索引数组和关联数组的值打印为带引号的键-值对序列(请参见数组)。https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
@K操作符之前使用[*][@]进行索引似乎没有任何区别。"${assoc[*]@K}""${assoc[@]@K}"都计算为同一个字符串。
还有@Q,但它只扩展到值,不包括键。
问:扩展是一个字符串,它是用引号括起来的参数值,格式可以重用为输入。
关联数组的另一个演示:

#!/bin/bash

function return_assoc() {
    declare -A assoc # Declaration required for associative arrays.
    assoc[zero]=0
    assoc[one]=1
    assoc[two]=2
    echo "${assoc[@]@K}" # Expand in key-value form.
}

# This printf statement will print each argument on it's own line.
printf "%s\n" "$(return_assoc)" # Only a single string is returned.

# Receive an associative array from a function:
declare -A assoc="($(return_assoc))"

echo "${assoc}" # Expansion should be empty, since it's an associative array.
echo "${assoc[@]@Q}" # Print all values.
echo "${assoc[@]@K}" # Print all key-value pairs.

# Loop through all keys in the array and print their values.
for a in "${!assoc[@]}"; do
    echo "assoc[${a}]=${assoc[${a}]}"
done

输出:

two "2" one "1" zero "0" 

'2' '1' '0'
two "2" one "1" zero "0" 
assoc[two]=2
assoc[one]=1
assoc[zero]=0

为了完整起见,下面是使用索引数组的相同演示:

function return_array() {
    declare -a array # Declaration optional for indexed arrays.
    array[0]=zero
    array[1]=one
    array[2]=two
    echo "${array[@]@Q}" # Expand in quoted form.
}

# This printf statement will print each argument on it's own line.
printf "%s\n" "$(return_array)" # Only a single string is returned.

# Receive an indexed array from a function:
declare -a array="($(return_array))"

echo "${array}" # Expands to the first element (array[0]).
echo "${array[@]@Q}" # Print all values.
echo "${array[@]@K}" # Print all index-value pairs.

# Loop through all values in the array.
for a in "${!array[@]}"; do
    echo "array[${a}]=${array[${a}]}"
done

输出:

'zero' 'one' 'two'
zero
'zero' 'one' 'two'
0 "zero" 1 "one" 2 "two"
array[0]=zero
array[1]=one
array[2]=two

相关问题