Я читал сценарий bash, который кто-то сделал, и заметил, что автор не использует eval для оценки переменной как команды
. Автор использовал
bash -c "$1"
вместо того
eval "$1"
Я предполагаю, что использование eval является предпочтительным методом, и в любом случае он, вероятно, быстрее. Это правда?
Есть ли практическая разница между ними? Каковы заметные различия между этими двумя?
bash
shell-script
bash-script
кто я
источник
источник
e='echo foo'; $e
работает просто отлично.Ответы:
eval "$1"
выполняет команду в текущем скрипте. Он может устанавливать и использовать переменные оболочки из текущего скрипта, устанавливать переменные среды для текущего скрипта, устанавливать и использовать функции из текущего скрипта, устанавливать текущий каталог, umask, пределы и другие атрибуты для текущего скрипта и так далее.bash -c "$1"
выполняет команду в совершенно отдельном сценарии, который наследует переменные среды, дескрипторы файлов и другую среду процесса (но не передает обратно никаких изменений), но не наследует внутренние параметры оболочки (переменные оболочки, функции, параметры, прерывания и т. д.).Есть другой способ,
(eval "$1")
который выполняет команду в подоболочке: он наследует все от вызывающего скрипта, но не передает никаких изменений обратно.Например, если предположить, что переменная
dir
не экспортирована и$1
естьcd "$foo"; ls
, то:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
перечисляет содержание/somewhere/else
и печатает/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
перечисляет содержание/somewhere/else
и печатает/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
перечисляет содержимое/starting/directory
(потомуcd ""
что не меняет текущий каталог) и печатает/starting/directory
.источник
(eval "$1")
имеет ничего общего сsource
. Это просто сочетание(…)
иeval
.source foo
примерно эквивалентноeval "$(cat foo)"
.eval
и.dot
заключается в том, что онeval
работает с аргументами и.dot
работает с файлами.Самое важное различие между
А также
Это первый работает в подоболочке, а второй нет. Так:
ВЫХОД:
ВЫХОД:
Я понятия не имею, почему кто-то когда-либо использовал исполняемый файл
bash
таким образом. Если вы должны вызвать его, используйте гарантированно встроенный POSIXsh
. Или(subshell eval)
если вы хотите защитить свою среду.Лично я предпочитаю оболочку
.dot
превыше всего.ВЫХОД
НО ЭТО ВАМ НУЖНО?
Единственная причина, по которой можно использовать либо, действительно, в том случае, если ваша переменная фактически назначает или оценивает другую, или разделение слов важно для вывода.
Например:
ВЫХОД:
Это работает, но только потому,
echo
что не заботится о количестве аргументов.ВЫХОД:
Видеть? Двойные кавычки приходят, потому что результат расширения оболочки
$var
не оценивается дляquote-removal
.ВЫХОД:
Но с
eval
илиsh
:ВЫХОД:
Когда мы используем
eval
или,sh
оболочка берет второй проход в результатах расширений и оценивает их как потенциальную команду, и поэтому кавычки имеют значение. Вы также можете сделать:ВЫХОД
источник
Я сделал быстрый тест:
(Да, я знаю, я использовал bash -c для выполнения цикла, но это не должно иметь никакого значения).
Результаты:
Так
eval
быстрее. Со страницы руководстваeval
:bash -c
конечно, выполняет команду в оболочке bash. Одно замечание: я использовал,/bin/echo
потому чтоecho
это встроенная оболочкаbash
, что означает, что новый процесс запускать не нужно. Замена/bin/echo
сecho
дляbash -c
тестирования, потребовалось1.28s
. Это примерно то же самое. Hovever,eval
быстрее для запуска исполняемых файлов. Ключевым отличием здесь является то,eval
что не запускается новая оболочка (она выполняет команду в текущей), тогда какbash -c
запускается новая оболочка, а затем выполняется команда в новой оболочке. Запуск новой оболочки требует времени, и поэтомуbash -c
медленнее, чемeval
.источник
bash -c
сeval
неexec
.bash -c
не что плохо ...