【问题标题】:Substition in Bash and associative arrayBash 和关联数组中的替换
【发布时间】:2021-08-15 18:18:23
【问题描述】:

我想动态声明和取消设置关联数组,但数组让我发疯,而且它们确实拥有最好的驾驶执照。 :-(

names=( Charlie Snoopy Linux Marcia )
intestines=$(printf "%s\n" ${names[@]} | awk '{ print "["$1"]="FNR  }' | tr "\n" " ")
echo $intestines # ok: [Charlie]=1 [Snoopy]=2 [Linux]=3 [Marcia]=4
unset namesAssociative
declare -A namesAssociative=( [Charlie]=1 [Snoopy]=2 [Linux]=3 [Marcia]=4 ) # works ok 
echo ${namesAssociative[Linux]} # OK: 3 

但是:

unset namesAssociative
declare -A namesAssociative=( $intestines ) # error
exec "declare -A namesAssociative=( $intestines )" # error
declare -A namesAssociative=( $(printf "%s\n" ${names[@]} | awk '{ print "["$1"]="FNR  }' | tr "\n" " ") ) # error
etc...

我猜是上帝惩罚了我,因为我从一开始就没有用 Python 写这个...... :-)

【问题讨论】:

  • declare -A "namesAssociative=( $intestines )" 在这种特殊情况下应该可以正常工作。一般来说,这是一种黑客行为,根本不可靠。
  • 当我重现您的案例时,namesAssociative 的声明会产生错误 bash: namesAssociative: $intestines: must use subscript when assignment associative array,我由此得出结论在这种情况下,参数扩展后不进行分词。我不知道为什么会这样,但我认为这是一个有效的问题。只是提到你得到“错误”,而不说是什么错误,并没有真正的帮助。顺便说一句,您的 exec 命令没有意义;您需要一个可执行文件作为参数。你的意思是eval 吗?
  • 是的,是的,是的。 eval 不执行... :-) 谢谢!

标签: bash associative-array substitution


【解决方案1】:

这可以按您的预期工作,并且使用关联数组键的 %q 格式指示符可以确保安全。

#!/usr/bin/env bash

names=( Charlie Snoopy Linux Marcia )

# shellcheck disable=SC2155 # Intended dynamic declaration
declare -A namesAssociative="($(
  for i in "${!names[@]}"; do
    printf '[%q]=%d ' "${names[i]}" $((i + 1))
  done
))"


declare -p namesAssociative

或者如果你的名字数组不是稀疏的:

declare -A namesAssociative="($(
  i=1
  for k in "${names[@]}"; do
    printf '[%q]=%d ' "$k" $((i++))
  done
))"

【讨论】:

  • 是的。这是错误:这有效:声明 -A namesAssociative="( $intestines )"。这不起作用:声明 -A namesAssociative=( "$intestines" )。这就是为什么它让我发疯...... :-) 谢谢 Lea!
【解决方案2】:

更简单的演示,将关联数组名称arr 放入列表中:

assoc_list="arr[first]=1 arr[second]=2 arr[third]=3"
unset arr
declare -A arr

eval $assoc_list

echo ${arr[second]}
2

稍后再演示设置关联数组名:

assoc_list="[first]=1 [second]=2 [third]=3"
# set associate array name as variable with value arr 
assoc_arr_name=arr
# create assoc_array_list from assoc_list
assoc_array_list=${assoc_list//[/$assoc_arr_name[}
echo $assoc_array_list
arr[first]=1 arr[second]=2 arr[third]=3


unset $assoc_arr_name
declare -A $assoc_arr_name

eval $assoc_array_list

echo ${arr[second]}
2

更一般的方式:

keys_arr=(first second third)
values_arr=(1 2 3)
map_name=assoc_arr
unset $map_name
declare -A $map_name
for ((i = 0 ; i < ${#keys_arr[@]} ; i++)); do 
    eval $map_name[${keys_arr[i]}]=${values_arr[i]};
done
echo ${assoc_arr[second]}
2

【讨论】:

    【解决方案3】:

    您过于强烈地坚持一次性从动态字符串文字创建数组,这取决于扩展顺序的各种特殊性,可能需要eval 或类似名称。

    也许不要那么用力,而是使用 for 循环:

    declare -a names=( Charlie Snoopy Linux Marcia )
    declare -Ai indices1 indices2  # to show two different options
    declare -i index
    
    for index in "${!names[@]}"; do
      indices1["${names[index]}"]=$((index + 1))      # option 1
      indices2+=(["${names[index]}"]=$((index + 1)))  # option 2
    done
    
    ((${#indices1[@]} == ${#indices2[@]})) || echo heck blah
    
    for name in "${!indices1[@]}"; do
      echo "${name}: $((indices1["${name}"])) $((indices2["${name}"]))"
    done
    

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多