Я хотел бы сохранить команду для использования в более поздний период в переменной (не вывод команды, а саму команду)
У меня есть простой сценарий:
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
Однако когда я пробую что-то посложнее, у меня ничего не получается. Например, если я сделаю
command="ls | grep -c '^'";
Результат:
Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory
Есть идеи, как сохранить такую команду (с трубами / несколькими командами) в переменной для последующего использования?
Ответы:
Используйте eval:
источник
backticks
. y = $ (eval $ x) mywiki.wooledge.org/BashFAQ/082eval
является приемлемой практикой, только если вы доверяете содержимому своих переменных. Если вы, скажем, работаетеx="ls $name | wc"
(или дажеx="ls '$name' | wc"
), то этот код - быстрый путь к уязвимостям внедрения или повышения привилегий, если эта переменная может быть установлена кем-то с меньшими привилегиями. (/tmp
Например, перебор всех подкаталогов в ? Лучше доверять каждому пользователю в системе, чтобы он не вызвал ни одного из них$'/tmp/evil-$(rm -rf $HOME)\'$(rm -rf $HOME)\'/'
).eval
является огромным магнитом для ошибок, который никогда не следует рекомендовать без предупреждения о риске неожиданного синтаксического анализа (даже без вредоносных строк, как в примере @ CharlesDuffy). Например, попробуйтеx='echo $(( 6 * 7 ))'
и потомeval $x
. Вы могли ожидать, что это напечатает «42», но, вероятно, этого не произойдет. Вы можете объяснить, почему это не работает? Вы можете объяснить, почему я сказал «вероятно»? Если ответы на эти вопросы для вас не очевидны, никогда не трогайтеeval
.set -x
заранее, чтобы записать выполненные команды, чтобы было легче увидеть, что происходит.Вы не использовать
eval
! Он имеет большой риск внедрения произвольного выполнения кода.BashFAQ-50 - Я пытаюсь поместить команду в переменную, но в сложных случаях всегда не получается.
Поместите его в массив и заключите все слова в двойные кавычки,
"${arr[@]}"
чтобы не допуститьIFS
разделения слов из-за разделения слов .и посмотреть содержимое массива внутри. Это
declare -p
позволяет вам видеть содержимое массива внутри с каждым параметром команды в отдельных индексах. Если один из таких аргументов содержит пробелы, цитирование внутри при добавлении в массив предотвратит его разделение из-за разделения слов.и выполните команды как
(или) полностью использовать
bash
функцию для запуска команды,и вызовите функцию просто
POSIX
sh
не имеет массивов, поэтому самое близкое, что вы можете сделать, - это создать список элементов в позиционных параметрах. Вотsh
способ POSIX для запуска почтовой программыОбратите внимание, что этот подход может обрабатывать только простые команды без перенаправлений. Он не может обрабатывать перенаправления, конвейеры, циклы for / while, операторы if и т. Д.
Другой распространенный вариант использования - запуск
curl
с несколькими полями заголовка и полезной нагрузкой. Вы всегда можете определить аргументы, как показано ниже, и вызватьcurl
содержимое расширенного массиваДругой пример,
теперь, когда переменные определены, используйте массив для хранения аргументов вашей команды
а теперь сделайте правильное цитируемое расширение
источник
Command=('echo aaa | grep a')
и"${Command[@]}"
, надеюсь, он запускает буквально командуecho aaa | grep a
. Это не так. Интересно, есть ли безопасный способ заменыeval
, но кажется, что каждое решение, имеющее такую же силу,eval
может быть опасным. Не так ли?Command() { echo aaa | grep a; }
- после чего вы можете просто запуститьCommand
, илиresult=$(Command)
, или что-то подобное.Используя этот метод, команда немедленно оценивается, и ее возвращаемое значение сохраняется.
То же самое с обратной кавычкой
Использование eval в
$(...)
не приведет к его оценке позжеИспользуя eval, он оценивается, когда
eval
используетсяВ приведенном выше примере, если вам нужно запустить команду с аргументами, поместите их в строку, которую вы сохраняете
Для сценариев bash это редко актуально, но последнее замечание. Будьте осторожны с
eval
. Оценивайте только те строки, которые вы контролируете, никогда строки, исходящие от ненадежного пользователя или созданные на основе ввода ненадежных пользователей.источник
eval $stored_date
может быть достаточно, когда онstored_date
только содержитdate
, ноeval "$stored_date"
намного надежнее. Запускstr=$'printf \' * %s\\n\' *'; eval "$str"
с и без кавычек вокруг окончательного"$str"
для примера. :)Для bash сохраните команду следующим образом:
Запустите вашу команду так:
источник
Я пробовал разные способы:
Вывод:
Как видите,
"$@"
правильный результат дал только третий .источник
Будьте внимательны, регистрируя заказ в:
X=$(Command)
Этот все еще выполняется Даже до вызова. Чтобы проверить и подтвердить это, вы можете сделать:
источник
источник
Нет необходимости хранить команды в переменных, даже если вам понадобится их использовать позже. просто выполните его как обычно. Если вы сохраняете переменную, вам понадобится какой-то
eval
оператор или вызовите какой-то ненужный процесс оболочки для «выполнения вашей переменной».источник
var='*.txt'; find . -name "$var"