Как я могу избежать произвольной строки для использования в качестве аргумента командной строки в Bash? - PullRequest
29 голосов
/ 10 июня 2011

У меня есть список строк, и я хочу передать эти строки в качестве аргументов в одном вызове командной строки Bash. Для простых буквенно-цифровых строк достаточно просто передать их дословно:

> script.pl foo bar baz yes no
foo
bar
baz
yes
no

Я понимаю, что если аргумент содержит пробелы, обратную косую черту или двойные кавычки, мне нужно использовать обратную косую черту, двойные кавычки и обратную косую черту, а затем двойные кавычки аргумента.

> script.pl foo bar baz "\"yes\"\\\"no\""
foo
bar
baz
"yes"\"no"

Но когда аргумент содержит восклицательный знак, это происходит:

> script.pl !foo
-bash: !foo: event not found

Двойное цитирование не работает:

> script.pl "!foo"
-bash: !foo: event not found

Также не экранируется обратная косая черта (обратите внимание, что в выводе присутствует буквенная обратная косая черта):

> script.pl "\!foo"
\!foo

Я пока мало что знаю о Баше, но знаю, что есть другие специальные персонажи, которые делают подобные вещи. Какова общая процедура безопасного экранирования произвольной строки для использования в качестве аргумента командной строки в Bash? Предположим, что строка может иметь произвольную длину и содержать произвольные комбинации специальных символов. Мне нужна подпрограмма escape(), которую я могу использовать, как показано ниже (пример Perl):

$cmd = join " ", map { escape($_); } @args;

Вот еще несколько примеров строк, которые должны быть безопасно экранированы этой функцией (я знаю, что некоторые из них выглядят как Windows, это преднамеренно):

yes
no
Hello, world      [string with a comma and space in it]
C:\Program Files\ [path with backslashes and a space in it]
"                 [i.e. a double-quote]
\                 [backslash]
\\                [two backslashes]
\\\               [three backslashes]
\\\\              [four backslashes]
\\\\\             [five backslashes]
"\                [double-quote, backslash]
"\T               [double-quote, backslash, T]
"\\T              [double-quote, backslash, backslash, T]
!1                
!A                
"!\/'"            [double-quote, exclamation, backslash, forward slash, apostrophe, double quote]
"Jeff's!"         [double-quote, J, e, f, f, apostrophe, s, exclamation, double quote]
$PATH             
%PATH%            
&                 
<>|&^             
*@$$A$@#?-_       

EDIT:

Это бы сработало? Избегайте каждого необычного символа с помощью обратной косой черты и пропускайте одинарные или двойные кавычки (Пример на Perl, но любой язык может сделать это)

sub escape {
    $_[0] =~ s/([^a-zA-Z0-9_])/\\$1/g;
    return $_[0];
}

Ответы [ 7 ]

19 голосов
/ 10 июня 2011

Если вы хотите безопасно указать что-нибудь для Bash, вы можете использовать его встроенный формат printf %q:

cat strings.txt:

yes
no
Hello, world
C:\Program Files\
"
\
\\
\\\
\\\\
\\\\\
"\
"\T
"\\T
!1
!A
"!\/'"
"Jeff's!"
$PATH
%PATH%
&
<>|&^
*@$$A$@#?-_

cat quote.sh:

#!/bin/bash
while IFS= read -r -d $'\n'
do
    printf %q "$REPLY"
    printf '\n'
done < strings.txt

./quote.sh:

yes
no
Hello\,\ world
C:\\Program\ Files\\
\"
\\
\\\\
\\\\\\
\\\\\\\\
\\\\\\\\\\
\"\\
\"\\T
\"\\\\T
\!1
\!A
\"\!\\/\'\"
\"Jeff\'s\!\"
\$PATH
%PATH%
\&
\<\>\|\&\^
\*@\$\$A\$@#\?-_

Эти строки могут быть дословно скопированы, например, echo для вывода исходных строк в strings.txt.

10 голосов
/ 27 ноября 2015

Какова общая процедура безопасного экранирования произвольной строки для использования в качестве аргумента командной строки в Bash?

Заменить каждое вхождение ' на '\'', затем поставить ' в начале и конце.

Каждый символ, кроме одной кавычки, может использоваться дословно в строке, разделенной одинарной кавычкой. Невозможно поместить одиночную кавычку в строку, разделенную одинарными кавычками, но это достаточно легко обойти: завершить строку ('), а затем добавить одиночную кавычку, используя обратную косую черту (\') ), затем начинайте новую строку (').

Насколько я знаю, это всегда будет работать, без исключений.

1 голос
/ 18 июня 2013

Всякий раз, когда вы видите, что не получаете желаемый результат, используйте следующий метод:

"""\special character"""

где специальный символ может включать ! " * ^ % $ # @ ....

Например, если вы хотите создать bash, генерирующий другой файл bash, в котором есть строка, и вы хотите присвоить ей значение, вы можете использовать следующий пример сценария:

Area="(1250,600),(1400,750)"
printf "SubArea="""\""""${Area}"""\""""\n" > test.sh
printf "echo """\$"""{SubArea}" >> test.sh

Тогда test.sh файл будет иметь следующий код:

SubArea="(1250,600),(1400,750)"
echo ${SubArea}

В качестве напоминания о новой строке \n мы должны использовать printf.

1 голос
/ 10 июня 2011
sub text_to_shell_lit(_) {
   return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/;
   my $s = $_[0];
   $s =~ s/'/'\\''/g;
   return "'$s'";
}

См. Это ранее post для примера.

1 голос
/ 10 июня 2011

Вы можете использовать одинарные кавычки, чтобы экранировать строки для Bash.Однако обратите внимание, что это не расширяет переменные внутри кавычек, как это делают двойные кавычки.В вашем примере должно работать следующее:

script.pl '!foo'

От Perl это зависит от функции, которую вы используете для запуска внешнего процесса.Например, если вы используете функцию system, вы можете передавать аргументы в качестве параметров, поэтому вам не нужно их экранировать. Конечно, вам все равно нужно экранировать кавычки для Perl:

system("/usr/bin/rm", "-fr", "/tmp/CGI_test", "/var/tmp/CGI");
0 голосов
/ 10 июня 2011

Это не полный ответ, но иногда полезно объединить два типа кавычек для одной строки, объединяя их, например echo "$HOME"'/foo!?.*'.

0 голосов
/ 10 июня 2011

Bash интерпретирует восклицательные знаки только в интерактивном режиме.

Вы можете предотвратить это, выполнив:

set +o histexpand

Внутри двойных кавычек вы должны избегать знаков доллара, двойных кавычек, обратной косой черты, и я быскажи, что все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...