[英]Indirect parameter substitution in shell script
我在使用 shell 脚本(HP-UX 下的 POSIX shell,FWIW)时遇到问题。 我有一个名为 print_arg 的函数,我将参数名称作为 $1 传递给该函数。 给定参数的名称,然后我想打印该参数的名称和值。 但是,我不断收到错误消息。 这是我正在尝试做的一个例子:
#!/usr/bin/sh
function print_arg
{
# $1 holds the name of the argument to be shown
arg=$1
# The following line errors off with
# ./test_print.sh[9]: argval=${"$arg"}: The specified substitution is not valid for this command.
argval=${"$arg"}
if [[ $argval != '' ]] ; then
printf "ftp_func: $arg='$argval'\n"
fi
}
COMMAND="XYZ"
print_arg "COMMAND"
我已经尝试以我能想到的各种方式重写违规行。 我咨询了当地的神谕。 我查看了在线“BASH 脚本指南”。 我磨快了那把波浪刃的刀,擦洗了祭坛,直到它闪闪发光,但后来我发现我们当地的处女供应已经减少到,就像,什么都没有。 讨厌!
任何关于如何获取其名称作为参数传递给函数的参数值的建议都将受到赞赏。
在 bash 中(但不是在其他 sh 实现中),间接通过以下方式完成: ${!arg}
foo=bar
bar=baz
echo $foo
echo ${!foo}
bar
baz
您可以使用eval
,但如果您可以使用bash
,则使用SiegeX 建议的直接间接可能会更好。
#!/bin/sh
foo=bar
print_arg () {
arg=$1
eval argval=\"\$$arg\"
echo "$argval"
}
print_arg foo
即使答案已经被接受,对于那些需要保留换行符和特殊字符(如 Escape ( \033
))的人来说,这是另一种方法:将变量存储在base64中。
你需要: bc、wc、echo、tail、tr、uuencode、uudecode
#!/bin/sh
#====== Definition =======#
varA="a
b
c"
# uuencode the variable
varB="`echo "$varA" | uuencode -m -`"
# Skip the first line of the uuencode output.
varB="`NUM=\`(echo "$varB"|wc -l|tr -d "\n"; echo -1)|bc \`; echo "$varB" | tail -n $NUM)`"
#====== Access =======#
namevar1=varB
namevar2=varA
echo simple eval:
eval "echo \$$namevar2"
echo simple echo:
echo $varB
echo precise echo:
echo "$varB"
echo echo of base64
eval "echo \$$namevar1"
echo echo of base64 - with updated newlines
eval "echo \$$namevar1 | tr ' ' '\n'"
echo echo of un-based, using sh instead of eval (but could be made with eval, too)
export $namevar1
sh -c "(echo 'begin-base64 644 -'; echo \$$namevar1 | tr ' ' '\n' )|uudecode"
simple eval:
a b c
simple echo:
YQpiCmMK ====
precise echo:
YQpiCmMK
====
echo of base64
YQpiCmMK ====
echo of base64 - with updated newlines
YQpiCmMK
====
echo of un-based, using sh instead of eval (but could be made with eval, too)
a
b
c
您也可以使用set
命令并解析它的输出; 这样,您无需在访问变量之前以特殊方式处理它。
使用eval
的更安全的解决方案:
v=1
valid_var_name='[[:alpha:]_][[:alnum:]_]*$'
print_arg() {
local arg=$1
if ! expr "$arg" : "$valid_var_name" >/dev/null; then
echo "$0: invalid variable name ($arg)" >&2
exit 1
fi
local argval
eval argval=\$$arg
echo "$argval"
}
print_arg v
print_arg 'v; echo test'
受到以下答案的启发。
这出奇的好:
#!/bin/sh
foo=bar
print_arg () {
local line name value
set | \
while read line; do
name=${line%=*} value=${line#*=\'}
if [ "$name" = "$1" ]; then
echo ${value%\'}
fi
done
}
print_arg foo
它具有 POSIX 的所有笨拙,在 Bash 中会更加分类,但话又说回来,你不需要它,因为你有${!}
。 这 -如果它被证明是可靠的 - 将具有仅使用内置函数而不使用eval
的优势。 如果我要使用外部命令构造这个函数,它必须是sed
。 将消除对读取循环和替换的需要。 请注意,在没有 eval 的情况下在 POSIX 中请求间接,必须付出笨拙的代价! 所以不要打我!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.