繁体   English   中英

Bash 变量扩展带变量

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM