Подтвердить что ты не робот

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

У меня есть список строк, и я хочу передать эти строки в качестве аргументов в одном вызове командной строки 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, но я знаю, что есть другие специальные персонажи, которые делают подобные вещи. Какова общая процедура безопасного экранирования произвольной строки для использования в качестве аргумента командной строки в 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%            
&                 
<>|&^             
*@[email protected]#?-_       

EDIT:

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

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

Ответ 1

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

cat strings.txt:

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

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\[email protected]#\?-_

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

Ответ 2

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

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

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

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

Ответ 3

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

script.pl '!foo'

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

system("/usr/bin/rm", "-fr", "/tmp/CGI_test", "/var/tmp/CGI");

Ответ 4

sub text_to_shell_lit(_) {
   return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/;
   my $s = $_[0];
   $s =~ s/'/'\\''/g;
   return "'$s'";
}

См. предыдущий post для примера.

Ответ 5

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

"""\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.

Ответ 6

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

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

set +o histexpand

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

Ответ 7

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