[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Подстановка переменного числа аргументов



On 28.10.2010 15:14, Serhiy Storchaka wrote:
Здравствуйте.

Прошу прощения за такой элементарный и не совсем тематический вопрос, но это
наиболее компетентная группа, которую я сейчас читаю.

Задача. В зависимости от некоторых условий необходимо вызвать команду с
дополнительными аргументами или без них. Например:

    if somecheck
    then
       OPTS="--foo $FOO"
    else
       OPTS=""
    fi
    bar -ziq $OPTS bla-bla-bla

Проблема в том, что $FOO может быть пустым (тогда подставится лишь один
аргумент --foo) или содержать пробелы (тогда подставится больше двух
аргументов).

Можно, конечно, написать:

    if somecheck
    then
       bar -ziq --foo "$FOO" bla-bla-bla
    else
       bar -ziq bla-bla-bla
    fi

И всё будет работать как надо. Но хотелось бы избежать дублирования,
постоянные аргументы вызова могут быть громоздкими. Не говоря уж о том, что
если будет несколько условий, код разрастётся в геометрической прогрессии.

Как быть?

Решение не красивое из-за примитивности самого shell-языка:

  $ var="--opt arg 'arg-part1 arg2-part2'"
  $ printarg $var
"printarg"
"--opt"
"arg"
"'arg-part1"
"arg2-part2'"
  $ sh -c "printarg $var"
"printarg"
"--opt"
"arg"
"arg-part1 arg2-part2"

Еще ограничение POSIX shell:

bash# foo=bar
bash# bar=xxx
bash# echo ${${foo}}
bash: ${${foo}}: bad substitution

или

bash# foo1=xxx
bash# foo2=yyy
bash# var=1
bash# echo ${foo${var}}
bash: ${foo${var}}: bad substitution

Для сравнения GNU Make раскрывает "по максимуму":

foo=bar
bar=xxx
$(error $($(foo)))

  $ make
Makefile:3: *** xxx.  Останов.

Интересно почитать про особенную переменную "$@" в двойных кавычках.

Нечто аналогичное делает утилита pathsearch, вот кусочек от туда:

[ -z "$_var" ] && _var=PATH
[ -z "$_delim" ] && _delim=":"

IFS="$_delim"
find=no
for token in `sh -c "echo \$""$_var"`; do    ## здесь интересно
  if [ -e "$token/$_pattern" ]; then
    find=yes
    echo "$token/$_pattern"
    continue
  fi
  if ls "$token"/$_pattern 2>/dev/null; then
    find=yes
  fi
done

[ $find = yes ] && exit 0 || exit 1

Вы можете передать имя переменной окружения в качестве аргумента утилите,
но раскрыть значение имени хранимого в параметре может следующий shell.

--
С уважением, Александр Гавенко.


Reply to: