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