eval
и exec
оба встроены в команды bash (1), которые выполняют команды.
Я также вижу, exec
есть несколько вариантов, но это единственная разница? Что происходит с их контекстом?
bash
shell
shell-builtin
Виллиан Пайшао
источник
источник
Ответы:
eval
иexec
совершенно разные звери. (Помимо того, что оба будут запускать команды, но так же, как и все, что вы делаете в оболочке.)То
exec cmd
же самое, что и просто запускcmd
, за исключением того, что текущая оболочка заменяется командой, а не отдельным запущенным процессом. Внутри работаю слово/bin/ls
будет вызывать ,fork()
чтобы создать дочерний процесс, а затемexec()
в ребенке выполнить/bin/ls
.exec /bin/ls
с другой стороны не будет вилка, а просто заменит оболочку.Для сравнения:
с участием
echo $$
печатает PID оболочки, которую я запустил, а листинг/proc/self
дает нам PID того,ls
что запускалось из оболочки. Обычно идентификаторы процессов разные, но сexec
оболочкой иls
имеют одинаковые идентификаторы процессов. Кроме того, следующая командаexec
не выполнялась, поскольку оболочка была заменена.С другой стороны:
eval
будет запускать аргументы как команду в текущей оболочке. Другими словамиeval foo bar
это то же самое, что и простоfoo bar
. Но переменные будут расширены перед выполнением, поэтому мы можем выполнять команды, сохраненные в переменных оболочки:Он не создаст дочерний процесс, поэтому переменная установлена в текущей оболочке. (Конечно
eval /bin/ls
, создаст дочерний процесс, так же, как обычный старый/bin/ls
.)Или у нас может быть команда, которая выводит команды оболочки. Запуск
ssh-agent
запускает агент в фоновом режиме и выводит набор переменных, которые могут быть установлены в текущей оболочке и использоваться дочерними процессами (ssh
команды, которые вы будете запускать). Следовательно,ssh-agent
можно начать с:И текущая оболочка получит переменные для наследования другими командами.
Конечно, если переменная
cmd
содержит нечто подобноеrm -rf $HOME
, то запускeval "$cmd"
не будет чем-то, что вы хотели бы сделать. Даже такие вещи, как подстановка команд внутри строки, будут обработаны, поэтому нужно действительно быть уверенным, что входные данныеeval
безопасны перед их использованием.Часто можно избежать
eval
и избежать даже случайного смешения кода и данных неправильным образом.источник
eval
в первую очередь для этого ответа тоже. Такие вещи, как косвенное изменение переменных, могут выполняться во многих оболочках черезdeclare
/typeset
/nameref
и подобные расширения${!var}
, поэтому я бы использовал их вместо техeval
случаев, когда мне действительно не пришлось этого избегать.exec
не создает новый процесс. Он заменяет текущий процесс новой командой. Если вы сделали это в командной строке, то это эффективно завершит сеанс оболочки (и, возможно, выйдет из системы или закроет окно терминала!)например
Вот и я
ksh
(моя нормальная оболочка). Я начинаю ,bash
а затем внутри Баш Iexec /bin/echo
. Мы можем видеть, что меня снова забросили,ksh
потому чтоbash
процесс был заменен на/bin/echo
.источник
TL; DR
exec
используется для замены текущего процесса оболочки новым и обработки перенаправления потока / файловых дескрипторов, если команда не указана.eval
используется для оценки строк как команд. Оба могут использоваться для построения и выполнения команды с аргументами, известными во время выполнения, ноexec
заменяют процесс текущей оболочки в дополнение к выполнению команд.встроенный exec
Синтаксис:
Согласно инструкции, если есть команда, указанная эта встроенная
Другими словами, если вы работали
bash
с PID 1234 и если вы должны были работатьexec top -u root
в этой оболочке,top
команда получит PID 1234 и заменит процесс вашей оболочки.Где это полезно? В чем-то, известном как сценарии оболочки. Такие сценарии создают наборы аргументов или принимают определенные решения о том, какие переменные передавать в среду, а затем используют
exec
для замены себя любой указанной командой и, конечно, предоставляют те же аргументы, которые создавал сценарий оболочки на этом пути.В руководстве также говорится, что:
Это позволяет нам перенаправить что-либо из текущих потоков вывода оболочек в файл. Это может быть полезно для целей регистрации или фильтрации, где вы не хотите видеть
stdout
команды, а толькоstderr
. Например, вот так:Такое поведение делает его удобным для входа в сценарии оболочки , перенаправления потоков в отдельные файлы или процессы и других забавных вещей с файловыми дескрипторами.
На уровне исходного кода, по крайней мере для
bash
версии 4.3,exec
встроенный определяется вbuiltins/exec.def
. Он анализирует полученные команды и, если они есть, передает данные вshell_execve()
функцию, определенную вexecute_cmd.c
файле.Короче говоря, на
exec
языке программирования C существует семейство команд, иshell_execve()
в основном это функция-оберткаexecve
:встроенный Eval
Руководство bash 4.3 гласит (выделено мной):
Обратите внимание, что не происходит замена процесса. В отличие от того,
exec
где цель состоит в том, чтобы симулироватьexecve()
функциональность,eval
встроенная функция служит только для «оценки» аргументов, как если бы пользователь вводил их в командной строке. Таким образом, новые процессы создаются.Где это может быть полезно? Как отметил Жиль в этом ответе , «... eval используется не очень часто. В некоторых оболочках наиболее распространенным способом является получение значения переменной, имя которой неизвестно до времени выполнения». Лично я использовал это в нескольких сценариях в Ubuntu, где было необходимо выполнить / оценить команду, основанную на конкретной рабочей области, которую пользователь использовал в настоящее время.
На уровне исходного кода он определяется
builtins/eval.def
и передает обработанную входную строку вevalstring()
функцию.Помимо прочего,
eval
может назначать переменные, которые остаются в текущей среде выполнения оболочки, ноexec
не могут:источник
А что? Весь смысл в
eval
том, что он никоим образом не создает дочерний процесс. Если я сделаюв оболочке, то после этого текущая оболочка сменит каталог. Ни один из них не
exec
создает новый дочерний процесс, вместо этого он изменяет текущий исполняемый файл (а именно оболочку) для данного; идентификатор процесса (и открытые файлы и другие вещи) остаются прежними. В противоположность этомуeval
, anexec
не будет возвращаться в вызывающую оболочку, еслиexec
сам не произойдет сбой из-за невозможности найти или загрузить исполняемый файл или умереть от проблем расширения аргументов.eval
в основном интерпретирует свой аргумент (аргументы) как строку после конкатенации, а именно он будет выполнять дополнительный уровень подстановочных знаков и разделения аргументов.exec
ничего такого не делает.источник
оценка
Эти работы:
Однако это не так:
Замена образа процесса
Этот пример демонстрирует, как
exec
заменяет изображение своего вызывающего процесса:Обратите внимание, что
exec echo $$
работает с PID подоболочки! Кроме того, после того, как это было завершено, мы вернулись в нашей первоначальнойsh$
оболочке.С другой стороны,
eval
это не заменит образа процесса. Скорее, он запускает данную команду, как обычно в самой оболочке. (Конечно, если вы запускаете команду, которая требует порождения процесса ... она делает это!)источник
exec
)