Что вы можете сделать с eval
командой? Почему это полезно? Это какая-то встроенная функция в bash? Там нет man
страницы для этого ..
help eval
получить страницу "man" из вашей оболочки
Что вы можете сделать с eval
командой? Почему это полезно? Это какая-то встроенная функция в bash? Там нет man
страницы для этого ..
help eval
получить страницу "man" из вашей оболочки
Ответы:
eval
является частью POSIX. Это интерфейс, который может быть встроенным в оболочку.
Это описано в «Руководстве программиста POSIX»: http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
Он примет аргумент и создаст его команду, которая будет выполняться оболочкой. Вот пример справочной страницы:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
$foo
значение '10'
и $x
значение 'foo'
.$y
, из чего состоит строка '$foo'
. Знак доллара должен быть экранирован '$'
.echo $y
.'$foo'
eval
. Сначала он будет оцениваться $x
в строку 'foo'
. Теперь у нас есть утверждение, y=$foo
которое будет оценено y=10
.echo $y
теперь является значением '10'
.Это распространенная функция во многих языках, например, Perl и JavaScript. Посмотрите на perldoc eval для других примеров: http://perldoc.perl.org/functions/eval.html
eval
это встроенная функция, а не функция. На практике встроенные модули ведут себя во многом подобно функциям, которые не имеют определения на языке, но не совсем (что становится очевидным, если вы достаточно искривлены, чтобы определить вызываемую функцию eval
).
Да, eval
это внутренняя команда bash, поэтому она описана на bash
странице руководства .
eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
Обычно он используется в сочетании с подстановкой команд . Без явного eval
, оболочка пытается выполнить результат подстановки команды, а не оценить его.
Скажите, что вы хотите закодировать эквивалент VAR=value; echo $VAR
. Обратите внимание на разницу в том, как оболочка обрабатывает записи echo VAR=value
:
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
Оболочка пытается выполнить echo
и VAR=value
две отдельные команды. Выдает ошибку о второй строке. Назначение остается неэффективным.
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
Оболочка объединяет (объединяет) две строки echo
и VAR=value
анализирует эту единицу в соответствии с соответствующими правилами и выполняет ее.Последнее, но не менее важное, eval
может быть очень опасной командой. Любой ввод в eval
команду должен быть тщательно проверен, чтобы избежать проблем безопасности.
eval
не имеет man-страницы, потому что это не отдельная внешняя команда, а скорее встроенная оболочка, то есть команда, внутренняя и известная только shell ( bash
). Соответствующая часть bash
справочной страницы гласит:
eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
Кроме того, вывод, если help eval
это:
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
eval
это мощная команда, и если вы намереваетесь ее использовать, вы должны быть очень осторожны, чтобы не допустить возможных рисков безопасности, связанных с ней.
Оператор eval говорит оболочке принять аргументы eval в качестве команды и выполнить их через командную строку. Это полезно в ситуации как ниже:
В вашем скрипте, если вы определяете команду в переменную, а затем хотите использовать эту команду, тогда вы должны использовать eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
ls | more
. Другими словами: одно имя команды состояло из девяти символов, включая пробелы и символ канала» .
eval - это команда оболочки, которая обычно реализуется как встроенная.
В POSIX он указан как часть «2.14. Специальные встроенные утилиты» в записи «eval» .
Что означает встроенное:
Термин «встроенный» подразумевает, что оболочка может запускать утилиту напрямую и не нуждается в ее поиске.
Проще говоря: делает входную строку для анализа дважды .
Оболочка имеет последовательность шагов, которые следует выполнить для «обработки» строки. Вы можете посмотреть на это изображение и понять, что eval - это единственная линия, которая идет вверх, к шагу 1 слева. Из описания POSIX :
2.1 Shell Введение
- Оболочка читает свой ввод ....
- Оболочка разбивает входные данные на токены: слова и операторы
- Оболочка анализирует ввод в простые и составные команды.
- Оболочка выполняет различные расширения (отдельно) ...
- Оболочка выполняет перенаправление и удаляет операторы перенаправления и их операнды из списка параметров.
- Оболочка выполняет функцию, встроенный, исполняемый файл или скрипт ...
- Оболочка по желанию ожидает завершения команды и собирает статус выхода.
На шаге 6 будет выполнен встроенный.
На шаге 6 eval вызывает отправку обработанной строки обратно на шаг 1.
Это единственное условие, при котором последовательность выполнения возвращается назад.
Вот почему я говорю: с eval входная строка анализируется дважды .
И самый важный эффект, чтобы понять. Является ли это следствием того, что в первый раз строка подвергается семи шагам оболочки, показанным выше, это цитирование . Внутри шага 4 (расширения) также есть последовательность шагов для выполнения всех расширений , последним из которых является Удаление цитаты :
Удаление цитаты всегда должно выполняться последним.
Таким образом, всегда есть один уровень цитирования удален.
Как следствие этого первого эффекта, дополнительные / различные части строки становятся доступными для разбора оболочки и всех других шагов.
Что позволяет выполнять косвенные расширения:
a=b b=c ; eval echo \$$a ### shall produce "c"
Почему? Потому что в первом цикле первый $
цитируется.
Как таковой, он игнорируется для расширений оболочкой.
Следующий $
с именем а раскрывается до «б».
Затем один уровень цитирования удаляется, в результате чего первый не $
цитируется.
Конец первого цикла.
Затем во втором цикле строка $b
читается оболочкой.
Затем расширили до «с»
и дали в качестве аргумента echo
.
Чтобы «увидеть», что eval будет производить в первом цикле (чтобы его можно было снова оценить), используйте echo. Или любая команда / скрипт / программа, которая четко показывает аргументы:
$ a=b b=c
$ eval echo \$$a;
c
Замените eval на echo, чтобы «увидеть», что происходит:
$ echo echo \$$a
echo $b
Также можно показать все «части» строки с помощью:
$ printf '<%s> ' echo \$$a
<echo> <$b>
В этом примере это только одно эхо и одна переменная, но помните об этом, чтобы помочь в оценке более сложных случаев.
Надо сказать, что: в приведенном выше коде есть ошибка, вы это видите?
Легко: отсутствуют некоторые цитаты.
Как? Вы можете спросить. Все просто, давайте изменим переменные (не код):
$ a=b b="hi jk"
$ eval echo \$$a
hi jk
Видишь пропущенные места?
Это потому, что значение внутри $b
было разделено оболочкой.
Если это не убедит вас, попробуйте это:
$ a=b b="hi * jk"
$ eval echo \$$a ### warning this will expand to the list
### of all files in the present directory.
Отсутствующие цитаты. Чтобы он работал правильно (добавьте внутренние "$a"
и внешние \"
кавычки).
Попробуйте это (совершенно безопасно):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
Для этого нет справочной страницы ..
Нет, для этого нет независимой справочной страницы. Поиск руководства с man -f eval
или даже не apropos eval
показывать запись.
Он включен внутри man bash
. Как и любой встроенный.
Ищите «SHELL BUILTIN COMMANDS», а затем «eval».
Более простой способ получить помощь: в bash вы можете help eval
обратиться за помощью к встроенному.
Потому что это привязка текста к коду динамически.
Другими словами: он преобразует список своих аргументов (и / или расширений таких аргументов) в исполняемую строку. Если по какой-либо причине злоумышленник установил аргумент, вы будете выполнять код злоумышленника.
Или даже проще, с помощью eval вы говорите, кто бы ни определил значение одного или нескольких аргументов:
Да ладно, сядь здесь и набери любую командную строку, я выполню ее своими силами.
Это опасно? Всем должно быть ясно, что это так.
Правило безопасности для eval должно быть таким:
Выполняйте eval только для переменных, которым вы дали его значение.
Подробнее читайте здесь .
eval
является чертой большинства интерпретируемых языков ( TCL
, python
, ruby
...), а не только снаряды. Он используется для динамической оценки кода.
В оболочках это реализовано как встроенная команда оболочки.
По сути, eval
принимает строку в качестве аргумента и оценивает / интерпретирует код в ней. В оболочках eval
может принимать более одного аргумента, но eval
просто объединяет их для формирования строки для оценки.
Он очень мощный, потому что вы можете динамически создавать код и запускать его, чего вы не можете делать в скомпилированных языках, таких как C.
Подобно:
varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
Но это также опасно, так как важно очистить динамические (предоставляемые извне) части того, что передается, по eval
той причине, что это интерпретируется как шелл-код.
Например, выше, если $1
есть evil-command; var
, eval
в конечном итоге evil-command; var=$varvalue
оцените код оболочки и затем запустите его evil-command
.
Злобность eval
часто преувеличивается.
ОК, это опасно, но, по крайней мере, мы знаем, что это опасно.
Много других команд будет оценивать код оболочки в его аргументы , если не продезинфицировать, например , ( в зависимости от оболочки), [
он же test
, export
, printf
, GNU sed
, awk
и, конечно , sh
/ bash
/ perl
и все переводчики ...
Примеры (здесь используются uname
как не предоставленные извне данные, так evil-command
и $a
предоставленные извне):
$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
Эти sed
, export
... команды могут считаться более опасными, потому что, хотя это очевидно eval "$var"
, из-за того, что содержимое $var
будет оцениваться как шелл-код, это не так очевидно с sed "s/foo/$var/"
или export "$var=value"
или [ "$var" -gt 0 ]
. Опасность та же, но она скрыта в других командах.
sed
подобно тому, как eval
передается строка, содержащаяся в переменной, и для обоих, содержимое этой строки в конечном итоге оценивается как шелл-код, поэтому sed
это так же опасно, как eval
и я. sed
передается строка, содержащая uname
(uname не был выполнен до сих пор) и через вызов sed
, команда uname заканчивается выполнением. Как для Eval. Во- sed 's/foo/$a/g'
первых, вы не передаете неанимированные данные sed
, это не то, о чем мы здесь говорим.
Этот пример может пролить некоторый свет:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
Вывод скрипта выше:
$VAR2
$VAR1
25
eval
. Верите ли вы, что есть какой-то фундаментальный, критический аспект функциональности, eval
который не описан в существующих ответах? Если так, то объясните это и используйте пример, чтобы проиллюстрировать ваше объяснение. Пожалуйста, не отвечайте в комментариях; отредактируйте свой ответ, чтобы сделать его более понятным и полным.
type command
чтобы узнать, какой тип команды . (type eval
в этом случае)