[英]Bash variable expansion with variable
我正在尝试使用 bash 的变量名扩展,但我似乎无法让它工作。 ${!${prefix}*}
特别是失败的原因。 下面是一个可重现的例子。
#!/bin/bash
MountVolumes_b_mkfs_options='foo bar baz'
MountVolumes_b_path=/foo/bar/baz
MountVolumes_b_mnt_options='foo bar baz'
MountVolumes_b_fs=xfs
MountVolumes_c_path=/foo/bar/baz
MountVolumes_c_fs=xfs
MountVolumes_c_mkfs_fs_options=-'t really -foo /ugly/options'
MountVolumes_c_mkfs_options='-t really -foo /ugly/options'
prefixes=($(echo "${!MountVolumes*}" | grep 'MountVolumes_[b-z]' -o | uniq))
for prefix in ${prefixes[@]}; do
echo "prefix: ${prefix}"
##I need this to expand to:
##MountVolumes_b_mkfs_options MountVolumes_b_path MountVolumes_b_mnt_options MountVolumes_b_fs
echo "${!${prefix}*}"
done
echo "${!MountVolumes_b*}" ##Works
我该怎么做呢?
这可以实现所需要的:
#!/bin/bash
MountVolumes_b_mkfs_options='foo bar baz'
MountVolumes_b_path=/foo/bar/baz
MountVolumes_b_mnt_options='foo bar baz'
MountVolumes_b_fs=xfs
MountVolumes_c_path=/foo/bar/baz
MountVolumes_c_fs=xfs
MountVolumes_c_mkfs_fs_options=-'t really -foo /ugly/options'
MountVolumes_c_mkfs_options='-t really -foo /ugly/options'
prefixes=($(echo "${!MountVolumes*}" | grep 'MountVolumes_[b-z]' -o | uniq))
for prefix in ${prefixes[@]}; do
echo "prefix: ${prefix}"
##I need this to expand to:
##MountVolumes_b_mkfs_options MountVolumes_b_path MountVolumes_b_mnt_options MountVolumes_b_fs
declare -a "vars=(\${!${prefix}*})"
echo "${vars[@]}"
done
echo "${!MountVolumes_b*}" ##Works
您会发现关联 arrays 更易于使用。
不幸的是 bash 没有给你嵌套的 arrays,但你可以这样做:
declare -A MountVolumes=(
[b]='
[fs]=xfs
[mkfs_options]="foo bar baz"
[mnt_options]="foo bar baz"
[path]=/foo/bar/baz
'
[c]='
[fs]=xfs
[mkfs_options]=-"t really -foo /ugly/options"
[mnt_options]="-t really -foo /ugly/options"
[path]=/foo/bar/baz
'
)
for prefix in "${!MountVolumes[@]}"; do
declare -A "tmp=( ${MountVolumes[$prefix]} )"
echo "prefix=$prefix, mkfs_options=${tmp[mkfs_options]}"
done
输出
prefix=c, mkfs_options=-t really -foo /ugly/options
prefix=b, mkfs_options=foo bar baz
我认为这是 go 的一种可读和可维护的方式。 报价可能会成为一个更大的问题。
由于变量已经在环境中,请尝试以下操作:
for prefix in {b..z}; do
if env | grep -q "^MountVolumes_${prefix}_"; then
declare -A tmp=()
for subvar in fs path mkfs_options mnt_options; do
var="MountVolumes_${prefix}_${subvar}"
tmp[$subvar]=${!var}
done
echo $prefix
declare -p tmp
fi
done
b
declare -A tmp=([path]="/foo/bar/baz" [fs]="xfs" [mnt_options]="foo bar baz" [mkfs_options]="foo bar baz" )
c
declare -A tmp=([path]="/foo/bar/baz" [fs]="xfs" [mnt_options]="" [mkfs_options]="-t really -foo /ugly/options" )
如果变量拼写一致,而不是MountVolumes_c_mkfs_fs_options
另一方面,如果您只关心变量名:
prefix=c
tmp="MountVolumes_${prefix}_@"
eval varnames=( "\${!$tmp}" )
这当然很恶心,但会导致
$ declare -p varnames
declare -a varnames=([0]="MountVolumes_c_fs" [1]="MountVolumes_c_mkfs_fs_options" [2]="MountVolumes_c_mkfs_options" [3]="MountVolumes_c_path")
我接受了答案,因为它解决了这个问题,但我最终以一种稍微不同的方式来做这件事,因为脚本注入具有相当严重的安全隐患。
在这里发布它以防它帮助任何人。
#!/bin/bash
MountVolumes_b_mkfs_options='foo bar baz'
MountVolumes_b_path=/foo/bar/baz
MountVolumes_b_mnt_options='foo bar baz'
MountVolumes_b_fs=xfs
MountVolumes_c_path=/foo/bar/baz
MountVolumes_c_fs=xfs
MountVolumes_c_mkfs_fs_options=-'t really -foo /ugly/options'
MountVolumes_c_mkfs_options='-t really -foo /ugly/options'
build_opt() {
key="${1}_${2}"
build_opt_res=" --${2} '${!key}'"
}
prefixes=($(echo "${!MountVolumes*}" | grep 'MountVolumes_[b-z]' -o | uniq))
for prefix in ${prefixes[@]}; do
build_opt "$prefix" "mkfs_options"
echo "${build_opt_res}"
build_opt "$prefix" "path"
echo "${build_opt_res}"
done
在 build_opt() 中从 ${.key} 中去掉单引号并硬编码已知的后缀应该可以消除脚本注入的可能性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.