Що ви можете зробити з 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
сторінці man.
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
не має довідної сторінки, оскільки це не окрема зовнішня команда, а скоріше вбудована оболонка, що означає внутрішню команду та відома лише оболонкою ( 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 Введення в оболонку
- Оболонка зчитує своє введення ....
- Оболонка розбиває введення в лексеми: слова та оператори
- Оболонка аналізує вхід на прості та складені команди.
- Оболонка виконує різні розширення (окремо) ...
- Оболонка виконує перенаправлення та видаляє операторів перенаправлення та їх операндів зі списку параметрів.
- Оболонка виконує функцію, вбудований, виконуваний файл або сценарій ...
- Оболонка необов'язково чекає, коли команда завершить, і збирає статус виходу.
На етапі 6 буде виконано вбудований модуль.
На етапі 6 eval викликає повернення оброблюваної лінії до етапу 1.
Це єдина умова, при якій послідовність виконання повертається назад.
Ось чому я кажу: З eval вхідний рядок аналізується двічі .
І найголовніший ефект, який потрібно зрозуміти. Чи є це одним із наслідків першого разу, коли рядок піддається семи етапам оболонки, показаним вище, цитуванням . Всередині кроку 4 (розширення) також є послідовність кроків для виконання всіх розширень , останній з яких - Видалення цитат :
Видалення котирувань завжди повинно виконуватися останнім.
Отже, завжди є один рівень котирування.
Як наслідок цього першого ефекту, додаткові / різні частини лінії піддаються розбору оболонки та всіх інших кроків.
Це дозволяє виконувати непрямі розширення:
a=b b=c ; eval echo \$$a ### shall produce "c"
Чому? Тому що на першому циклі $
цитується перший .
Таким чином, оболонка ігнорується для розширень.
Наступний $
з назвою a розгорнуто для отримання "b".
Потім один рівень котирування видаляється, роблячи перший без $
котирування.
Кінець першої петлі.
Саме тоді на другому циклі рядок $b
зчитується оболонкою.
Потім розширено на "с"
і подано як аргумент до echo
.
Щоб "побачити", що eval створить на першому циклі (оцінюється ще раз), використовуйте ехо. Або будь-яка команда / сценарій / програма, яка чітко показує аргументи:
$ a=b b=c
$ eval echo \$$a;
c
Замініть eval на відлуння, щоб "побачити", що відбувається:
$ 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
. Як і будь-який вбудований.
Шукайте "ЗРОБИТИ БУЛІТИННІ КОМАНДИ", а потім - "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'
, ви не передаєте unsanitized даних на 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
у цьому випадку)