Большинство этих ответов касаются конкретного случая, о котором вы спрашиваете. Существует общий подход, который разработали мы с другом, который позволяет использовать произвольные кавычки в случае, если вам нужно цитировать команды bash через несколько уровней расширения оболочки, например, через ssh, su -c
, bash -c
и т. Д. Вам нужен один базовый примитив. , здесь в родном bash:
quote_args() {
local sq="'"
local dq='"'
local space=""
local arg
for arg; do
echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
space=" "
done
}
Это делает именно то, что он говорит: он заключает в кавычки каждый аргумент индивидуально (после расширения bash, конечно):
$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'
Это очевидная вещь для одного уровня расширения:
$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2
(Обратите внимание, что двойные кавычки вокруг $(quote_args ...)
необходимы, чтобы преобразовать результат в единственный аргумент для bash -c
.) И его можно использовать в более общем плане для правильного цитирования через несколько уровней раскрытия:
$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2
Приведенный выше пример:
- оболочка заключает в кавычки каждый аргумент внутреннего
quote_args
по отдельности, а затем объединяет результирующий вывод в один аргумент с внутренними двойными кавычками.
- shell-кавычки
bash
, -c
и уже однажды заключенный в кавычки результат шага 1, а затем объединяет результат в один аргумент с внешними двойными кавычками.
- отправляет этот беспорядок в качестве аргумента внешнему
bash -c
.
Это вкратце идея. Вы можете делать с этим довольно сложные вещи, но вы должны быть осторожны с порядком оценки и с тем, какие подстроки цитируются. Например, следующие действия делают неправильные вещи (для некоторого определения «неправильного»):
$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure
В первом примере bash немедленно расширяет quote_args cd /; pwd 1>&2
на две отдельные команды, quote_args cd /
и pwd 1>&2
, так что CWD по-прежнему /tmp
, когда выполняется команда pwd
. Второй пример иллюстрирует аналогичную проблему для подстановки. Действительно, та же самая основная проблема возникает со всеми расширениями bash. Проблема здесь в том, что подстановка команды не является вызовом функции: она буквально оценивает один сценарий bash и использует его выходные данные как часть другого сценария bash.
Если вы попытаетесь просто избежать операторов оболочки, вы потерпите неудачу, потому что результирующая строка, переданная в bash -c
, представляет собой просто последовательность строк, заключенных в индивидуальные кавычки, которые затем не интерпретируются как операторы, что легко увидеть, если вы повторите строку, которая было бы передано в bash:
$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'
Проблема здесь в том, что вы цитируете слишком много. Вам нужно, чтобы операторы не заключались в кавычки в качестве входных данных для включающего bash -c
, что означает, что они должны находиться вне подстановки команд $(quote_args ...)
.
Следовательно, что вам нужно сделать в самом общем смысле, так это заключить в кавычки каждое слово команды, не предназначенное для расширения во время подстановки команды отдельно, и не применять какие-либо дополнительные кавычки к операторам оболочки:
$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success
Как только вы это сделаете, вся строка станет честной игрой для дальнейшего цитирования с произвольными уровнями оценки:
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success
и т.п.
Эти примеры могут показаться излишними, учитывая, что такие слова, как success
, sbin
и pwd
не нужно заключать в кавычки, но ключевой момент, который следует помнить при написании сценария с произвольным вводом, заключается в том, что вы хотите цитировать все, что вы не совсем конечно, не нуждается в цитировании, потому что вы никогда не знаете, когда пользователь вставит Robert'; rm -rf /
.
Чтобы лучше понять, что происходит под обложками, вы можете поиграть с двумя небольшими вспомогательными функциями:
debug_args() {
for (( I=1; $I <= $#; I++ )); do
echo -n "$I:<${!I}> " 1>&2
done
echo 1>&2
}
debug_args_and_run() {
debug_args "$@"
"$@"
}
который перечислит каждый аргумент команды перед ее выполнением:
$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
person
Kyle Rose
schedule
29.12.2015
"\""
, поэтому их следует использовать, когда это возможно, вместо ответа @ liori. - person alan   schedule 20.10.2017