Який правильний спосіб викликати якусь команду, що зберігається у змінній?
Чи є відмінності між 1 і 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Який правильний спосіб викликати якусь команду, що зберігається у змінній?
Чи є відмінності між 1 і 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Відповіді:
Оболонки Unix виконують серію перетворень на кожному рядку вводу перед їх виконанням. Для більшості оболонок це виглядає приблизно так (взято з сторінки bash
):
Використання $cmd
безпосередньо замінює його на вашу команду під час фази розширення параметрів, а потім воно зазнає всіх наступних перетворень.
Використання eval "$cmd"
не робить нічого до фази видалення котирувань, де $cmd
повертається як є і передається як параметр eval
, чия функція полягає в тому, щоб знову запускати весь ланцюжок перед виконанням.
Отже, в основному вони однакові в більшості випадків і різняться, коли ваша команда використовує кроки перетворення аж до розширення параметрів. Наприклад, за допомогою розширення фігурної дужки:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval "$cmd"
без письма eval
? $($cmd)
? ${$cmd}
?
eval
Операція аналізує дані як синтаксис; отже, це дуже чутливо до безпеки, і робити це неявно було б дуже поганою формою.
Якщо ви просто робите, eval $cmd
коли ми це робимо cmd="ls -l"
(інтерактивно та за допомогою сценарію), ми отримуємо бажаний результат. У вашому випадку у вас є труба з grep без шаблону, тому grep частина вийде з ладу з повідомленням про помилку. Просто $cmd
згенерує повідомлення "команда не знайдена" (або якесь таке). Тож спробуйте використовувати eval і використовувати готову команду, а не таку, яка генерує повідомлення про помилку.
$cmd
просто замінить змінну на значення, яке буде виконано в командному рядку.
eval "$cmd"
виконує розширення змінних та заміну команд перед виконанням отриманого значення в командному рядку
Другий метод корисний, коли ви хочете запускати команди, які не є гнучкими, наприклад.
for i in {$a..$b}
Цикл формату не буде працювати, оскільки він не допускає змінних.
У цьому випадку труба для удару чи виправлення є обхідним шляхом.
Перевірено на Mac OSX 10.6.8, Bash 3.2.48
Я думаю, вам слід поставити
`
(зворотні позначки) навколо вашої змінної.