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