Как правильно вызвать команду, хранящуюся в переменной?
Есть ли разница между 1 и 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Как правильно вызвать команду, хранящуюся в переменной?
Есть ли разница между 1 и 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Ответы:
Оболочки Unix перед их выполнением выполняют серию преобразований в каждой строке ввода. Для большинства оболочек это выглядит примерно так (взято из bash
справочной страницы):
Использование $cmd
напрямую заменяет его вашей командой на этапе раскрытия параметров, а затем он претерпевает все последующие преобразования.
Использование eval "$cmd"
ничего не делает до фазы удаления цитаты, где $cmd
возвращается как есть и передается в качестве параметра eval
функции, чья функция заключается в повторном запуске всей цепочки перед выполнением.
В общем, в большинстве случаев они одинаковы и различаются, когда ваша команда использует шаги преобразования вплоть до раскрытия параметров. Например, используя раскладку скобок:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval "$cmd"
без письма eval
? $($cmd)
? ${$cmd}
?
eval
операция анализирует данные как синтаксис; поэтому он очень чувствителен к безопасности, и делать это неявно было бы очень плохим тоном.
Если вы просто сделаете это, eval $cmd
когда мы это сделаем cmd="ls -l"
(в интерактивном режиме и в сценарии), мы получим желаемый результат. В вашем случае у вас есть канал с grep без шаблона, поэтому часть grep выйдет из строя с сообщением об ошибке. Просто $cmd
создаст сообщение «команда не найдена» (или что-то подобное). Поэтому попробуйте использовать eval и использовать готовую команду, а не ту, которая генерирует сообщение об ошибке.
$cmd
просто заменит переменную ее значением, которое будет выполнено в командной строке.
eval "$cmd"
выполняет расширение переменных и подстановку команд перед выполнением результирующего значения в командной строке
Второй метод полезен, когда вы хотите запускать команды, которые не являются гибкими, например.
for i in {$a..$b}
Цикл форматирования не будет работать, потому что он не позволяет использовать переменные.
В этом случае обходной путь является использование канала для bash или eval.
Протестировано на Mac OSX 10.6.8, Bash 3.2.48
Я думаю тебе стоит поставить
`
(обратная кавычка) вокруг вашей переменной.