我在 Solaris 10 计算机上使用 Ksh88。
如果我执行以下操作:
foo="one two three"
for i in $foo; do
echo $i;
done
该脚本按预期执行:
$ ./script.ksh
one
two
three
但是,如果我用这个替换循环:
foo="one two three"
for i in $(sed -e 's/bar/$foo/' <(echo $1));
do
echo $i
done
我执行它,这就是我得到的:
$ ./script.ksh bar
$foo
如何将命令for
的结果扩展sed
为变量?
答案1
sed -e 's/bar/$foo/' <(echo $1)
印刷$foo
。命令扩展的结果不受 shell 语法处理的影响。当您在双引号之外使用这种方式时,它仅受字段拆分(拆分为单词)文件名生成(即通配符)的影响。
在任何 shell 中,如果一个变量的名称存在于另一个变量中,则可以使用 获取该变量的值eval
。
variable_name=$(sed -e 's/bar/foo/' <(echo $1))
case $variable_name in
*[!0-9A-Z_a-z]*) echo 1>&2 "Invalid variable name: $variable_name"; exit 3;;
esac
eval variable_value="\${$variable_name}"
for i in $variable_value; do …
请注意,$variable_value
不仅将值分解为空格分隔的部分,而且还在这些部分上执行通配符(即将通配符扩展为文件名)。要关闭通配符,请set +f
提前致电。
在 ksh93 中,定义变量时可以使用一个特殊标志var
,它告诉 shell 变量的值本身就是一个变量名,并且$var
必须扩展到名称为 的变量的值$var
。另外,您应该创建foo
一个数组,因为它实际上是字符串列表而不是字符串。
foo=(one two three)
typeset -n variable_name="$(sed -e 's/bar/foo/' <(echo $1))"
for i in "${variable_name[@]}"; do …
答案2
foo=$(echo "$foo" | sed 's/[\\\/]/\\&/g') # only required if $foo can contain one of \/
set +f # only required if $foo contains one of \[*?
for i in $(echo "$1" | sed -e "s/bar/$foo/"); do
echo $i
done