Косвенная подстановка параметров в сценарии оболочки - PullRequest
2 голосов
/ 07 декабря 2010

У меня проблема со сценарием оболочки (оболочка POSIX под HP-UX, 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". И я заточил старый нож с волнистым лезвием и вычистил алтарь, пока он не поблескивал, но потом я обнаружил, что наш местный запас девственниц был сокращен до ничего. Убирайся!

Любые советы относительно того, как получить значение параметра, имя которого передается в функцию в качестве параметра, будут приняты с благодарностью.

Ответы [ 4 ]

9 голосов
/ 07 декабря 2010

В bash (но не в других реализациях sh) перенаправление осуществляется с помощью: ${!arg}

Вход

foo=bar
bar=baz

echo $foo
echo ${!foo}

Выход

bar
baz
7 голосов
/ 07 декабря 2010

Вы можете использовать eval, хотя используйте прямое косвенное обращение, так как , предложенное SiegeX , вероятно, будет лучше, если вы можете использовать bash.

#!/bin/sh

foo=bar
print_arg () {
    arg=$1
    eval argval=\"\$$arg\"
    echo "$argval"
}
print_arg foo
1 голос
/ 17 июля 2013

Несмотря на то, что ответ уже принят, вот еще один метод для тех, кому необходимо сохранить символы новой строки и специальные символы, такие как 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 и проанализировать ее вывод; при этом вам не нужно обрабатывать переменную особым образом, прежде чем она будет доступна.

1 голос
/ 18 ноября 2011

Это сработало на удивление хорошо:

#!/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 он будет намного более сортировочным, но опять же, он вам не понадобится, поскольку у вас есть ${!}. Это - в случае, если оно окажется твердым - будет иметь преимущество в использовании только встроенных функций и no eval. Если бы я должен был построить эту функцию, используя внешнюю команду, это должно было бы быть sed. Избавит от необходимости цикл чтения и замены. Имейте в виду, что запрос на перенаправления в POSIX без Eval, должен быть оплачен с грубостью! Так что не бей меня!

...