Bash 和关联数组中的替换
Substition in Bash and associative array
我想动态声明和取消设置关联数组,但数组让我发疯,而且他们确实有最好的驾驶执照。 :-(
names=( Charlie Snoopy Linux Marcia )
intestines=$(printf "%s\n" ${names[@]} | awk '{ print "[""]="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 "[""]="FNR }' | tr "\n" " ") ) # error
etc...
我想上帝在惩罚我,因为我没有从一开始就在 Python 中写...:-)
这正如您所期望的那样工作,并且使用关联数组键的 %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
))"
更简单的演示,将关联数组名称 arr
放入列表中:
assoc_list="arr[first]=1 arr[second]=2 arr[third]=3"
unset arr
declare -A arr
eval $assoc_list
echo ${arr[second]}
2
另一个demo设置关联数组名稍后:
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
您过于坚持从动态字符串文字一次性创建数组,这取决于展开顺序的各种特性,可能需要 eval
等。
也许不要太用力,而是使用 for-cycle 代替:
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
我想动态声明和取消设置关联数组,但数组让我发疯,而且他们确实有最好的驾驶执照。 :-(
names=( Charlie Snoopy Linux Marcia )
intestines=$(printf "%s\n" ${names[@]} | awk '{ print "[""]="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 "[""]="FNR }' | tr "\n" " ") ) # error
etc...
我想上帝在惩罚我,因为我没有从一开始就在 Python 中写...:-)
这正如您所期望的那样工作,并且使用关联数组键的 %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
))"
更简单的演示,将关联数组名称 arr
放入列表中:
assoc_list="arr[first]=1 arr[second]=2 arr[third]=3"
unset arr
declare -A arr
eval $assoc_list
echo ${arr[second]}
2
另一个demo设置关联数组名稍后:
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
您过于坚持从动态字符串文字一次性创建数组,这取决于展开顺序的各种特性,可能需要 eval
等。
也许不要太用力,而是使用 for-cycle 代替:
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