簡體   English   中英

shell腳本中的間接參數替換

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM