Как выполнить команду, хранящуюся в переменной? - PullRequest
73 голосов
/ 12 января 2011

Как правильно вызвать команду, хранящуюся в переменной?
Есть ли различия между 1 и 2?

#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"

Ответы [ 4 ]

85 голосов
/ 12 января 2011

Оболочки Unix выполняют серию преобразований в каждой строке ввода перед их выполнением. Для большинства оболочек это выглядит примерно так (взято из справочной страницы bash):

  • начальное разбиение слова
  • расширение скобки
  • расширение тильды
  • параметр, переменное и арифметическое расширение
  • подстановка команд
  • вторичное разделение слов
  • расширение пути (или глобализация)
  • удаление цитаты

Использование $cmd напрямую заменяет его вашей командой во время фазы расширения параметра, а затем он подвергается всем следующим преобразованиям.

Использование eval "$cmd" ничего не делает до фазы удаления кавычек, где $cmd возвращается как есть и передается в качестве параметра eval, функция которого - снова выполнить всю цепочку перед выполнением.

Таким образом, в основном они одинаковы в большинстве случаев и отличаются, когда ваша команда использует шаги преобразования вплоть до раскрытия параметров. Например, используя расширение скобки:

$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
5 голосов
/ 12 января 2011

Если вы просто сделаете eval $cmd когда мы делаем cmd="ls -l" (в интерактивном режиме и в сценарии), мы получаем желаемый результат. В вашем случае у вас есть канал с grep без шаблона, поэтому часть grep выдает сообщение об ошибке. Просто $cmd сгенерирует сообщение «команда не найдена» (или что-то подобное). Поэтому попробуйте использовать eval и использовать готовую команду, а не ту, которая генерирует сообщение об ошибке.

0 голосов
/ 18 июня 2019

$cmd просто заменит переменную на значение, которое будет выполнено в командной строке.eval "$cmd" выполняет расширение переменной и подстановку команд перед выполнением результирующего значения в командной строке

2-й метод полезен, когда вы хотите выполнить команды, которые не являются гибкими, например.
for i in {$a..$b}
цикл форматирования не будет работать, потому что он не допускает переменные.
В этом случае обходной путь - bash или eval.

Протестировано на Mac OSX 10.6.8, Bash 3.2.48

0 голосов
/ 12 января 2011

Я думаю, вы должны поставить

`

(backtick) символы вокруг вашей переменной.

...