it-swarm.com.ru

Какие символы необходимо экранировать при использовании Bash?

Есть ли исчерпывающий список символов, которые нужно экранировать в Bash? Это можно проверить только с помощью sed?

В частности, я проверял, нужно ли экранировать % или нет. Я старался

echo "h%h" | sed 's/%/i/g'

и работал нормально, без экранирования %. Означает ли это, что % не нужно экранировать? Был ли это хороший способ проверить необходимость?

И более общий: являются ли они одинаковыми символами, которые нужно экранировать в Shell и bash?

150
fedorqui

Есть два простых и безопасных правила, которые работают не только в sh, но также bash.

1. Поместите всю строку в одинарные кавычки

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

'I'\''m a [email protected] $tring which ends in newline
'

команда sed: sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"

2. Избегайте каждого символа с обратной косой чертой

Это работает для всех персонажей, кроме новой строки. Для символов новой строки используйте одинарные или двойные кавычки. Пустые строки по-прежнему должны обрабатываться - замените ""

\I\'\m\ \a\ \s\@\f\e\ \$\t\r\i\n\g\ \w\h\i\c\h\ \e\n\d\s\ \i\n\ \n\e\w\l\i\n\e"
"

команда sed: sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.

2b. Более читаемая версия 2

Существует простой безопасный набор символов, например [a-zA-Z0-9,._+:@%/-], который можно оставить без экранирования, чтобы сделать его более читабельным

I\'m\ a\ [email protected]\ \$tring\ which\ ends\ in\ newline"
"

команда sed: LC_ALL=C sed -e 's/[^a-zA-Z0-9,[email protected]%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.


Обратите внимание, что в программе sed невозможно узнать, заканчивается ли последняя строка ввода байтом новой строки (кроме случаев, когда он пуст). Вот почему обе приведенные выше команды sed предполагают, что это не так. Вы можете добавить цитируемую новую строку вручную.

Обратите внимание, что переменные оболочки определены только для текста в смысле POSIX. Обработка двоичных данных не определена. Для реализаций, которые имеют значение, двоичный код работает, за исключением байтов NUL (поскольку переменные реализованы с помощью строк C и предназначены для использования в качестве строк C, а именно аргументов программы), но вам следует переключиться на "двоичный" языковой стандарт, такой как latin1 ,.


(Вы можете легко проверить правила, прочитав спецификацию POSIX для sh. Для bash обратитесь к справочному руководству, связанному с @AustinPhillips)

206
Jo So

формат, который можно использовать в качестве ввода для оболочки

Для этого типа запроса создана директива формата specialprintf (%q):

printf [-v var] формат [аргументы]

 %q     causes printf to output the corresponding argument
        in a format that can be reused as Shell input.

Некоторые образцы:

read foo
Hello world
printf "%q\n" "$foo"
Hello\ world

printf "%q\n" $'Hello world!\n'
$'Hello world!\n'

Это можно использовать и через переменные:

printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'

Быстрая проверка со всеми (128) байтами ascii:

Обратите внимание, что все байты от 128 до 255 должны быть экранированы.

for i in {0..127} ;do
    printf -v var \\%o $i
    printf -v var $var
    printf -v res "%q" "$var"
    esc=E
    [ "$var" = "$res" ] && esc=-
    printf "%02X %s %-7s\n" $i $esc "$res"
done |
    column

Это должно сделать что-то вроде:

00 E ''         1A E $'\032'    34 - 4          4E - N          68 - h      
01 E $'\001'    1B E $'\E'      35 - 5          4F - O          69 - i      
02 E $'\002'    1C E $'\034'    36 - 6          50 - P          6A - j      
03 E $'\003'    1D E $'\035'    37 - 7          51 - Q          6B - k      
04 E $'\004'    1E E $'\036'    38 - 8          52 - R          6C - l      
05 E $'\005'    1F E $'\037'    39 - 9          53 - S          6D - m      
06 E $'\006'    20 E \          3A - :          54 - T          6E - n      
07 E $'\a'      21 E \!         3B E \;         55 - U          6F - o      
08 E $'\b'      22 E \"         3C E \<         56 - V          70 - p      
09 E $'\t'      23 E \#         3D - =          57 - W          71 - q      
0A E $'\n'      24 E \$         3E E \>         58 - X          72 - r      
0B E $'\v'      25 - %          3F E \?         59 - Y          73 - s      
0C E $'\f'      26 E \&         40 - @          5A - Z          74 - t      
0D E $'\r'      27 E \'         41 - A          5B E \[         75 - u      
0E E $'\016'    28 E \(         42 - B          5C E \\         76 - v      
0F E $'\017'    29 E \)         43 - C          5D E \]         77 - w      
10 E $'\020'    2A E \*         44 - D          5E E \^         78 - x      
11 E $'\021'    2B - +          45 - E          5F - _          79 - y      
12 E $'\022'    2C E \,         46 - F          60 E \`         7A - z      
13 E $'\023'    2D - -          47 - G          61 - a          7B E \{     
14 E $'\024'    2E - .          48 - H          62 - b          7C E \|     
15 E $'\025'    2F - /          49 - I          63 - c          7D E \}     
16 E $'\026'    30 - 0          4A - J          64 - d          7E E \~     
17 E $'\027'    31 - 1          4B - K          65 - e          7F E $'\177'
18 E $'\030'    32 - 2          4C - L          66 - f      
19 E $'\031'    33 - 3          4D - M          67 - g      

Если первое поле является шестнадцатеричным значением байта, второе содержит E, если требуется экранировать символ, а третье поле показывает экранированное представление символа.

Почему ,?

Вы могли видеть некоторые символы, которые всегда не нужно экранировать, например ,, } и {.

Так что не всегда но иногда:

echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.

или же

echo test { 1, 2, 3 }
test { 1, 2, 3 }

но все равно

echo test{1,2,3}
test1 test2 test3

echo test\ {1,2,3}
test 1 test 2 test 3

echo test\ {\ 1,\ 2,\ 3\ }
test  1 test  2 test  3

echo test\ {\ 1\,\ 2,\ 3\ }
test  1, 2 test  3 
37
F. Hauri

Чтобы избавить кого-то от необходимости использовать RTFM ... in bash:

Заключение символов в двойные кавычки сохраняет буквальное значение всех символов в кавычках, за исключением $, `, \ и, когда расширение истории включено, !.

... так что если вы избежите этого (и сама цитата, конечно), вы, вероятно, в порядке.

Если вы придерживаетесь более консервативного подхода "когда сомневаетесь, избегайте его", следует избегать использования символов с особым значением, не избегая идентифицирующих символов (т. Е. ASCII букв, цифр или '_'). ). Очень маловероятно, что они когда-либо (то есть в какой-то странной оболочке POSIX-ish) будут иметь особое значение и, следовательно, должны быть экранированы.

29
Matthew

Используя print '%q'технику , мы можем запустить цикл, чтобы выяснить, какие символы особенные:

#!/bin/bash
special=$'`[email protected]#$%^&*()-_+={}|[]\\;\':",.<>?/ '
for ((i=0; i < ${#special}; i++)); do
    char="${special:i:1}"
    printf -v q_char '%q' "$char"
    if [[ "$char" != "$q_char" ]]; then
        printf 'Yes - character %s needs to be escaped\n' "$char"
    else
        printf 'No - character %s does not need to be escaped\n' "$char"
    fi
done | sort

Это дает такой вывод:

No, character % does not need to be escaped
No, character + does not need to be escaped
No, character - does not need to be escaped
No, character . does not need to be escaped
No, character / does not need to be escaped
No, character : does not need to be escaped
No, character = does not need to be escaped
No, character @ does not need to be escaped
No, character _ does not need to be escaped
Yes, character   needs to be escaped
Yes, character ! needs to be escaped
Yes, character " needs to be escaped
Yes, character # needs to be escaped
Yes, character $ needs to be escaped
Yes, character & needs to be escaped
Yes, character ' needs to be escaped
Yes, character ( needs to be escaped
Yes, character ) needs to be escaped
Yes, character * needs to be escaped
Yes, character , needs to be escaped
Yes, character ; needs to be escaped
Yes, character < needs to be escaped
Yes, character > needs to be escaped
Yes, character ? needs to be escaped
Yes, character [ needs to be escaped
Yes, character \ needs to be escaped
Yes, character ] needs to be escaped
Yes, character ^ needs to be escaped
Yes, character ` needs to be escaped
Yes, character { needs to be escaped
Yes, character | needs to be escaped
Yes, character } needs to be escaped

Некоторые результаты, такие как ,, выглядят немного подозрительно. Было бы интересно получить отзывы @ CharlesDuffy по этому вопросу.

20
codeforester

Символы, которые нужно экранировать, отличаются в Bourne или POSIX Shell от Bash. Обычно (очень) Bash является надмножеством этих оболочек, поэтому все, что вы экранируете в Shell, должно быть экранировано в Bash.

Хорошим общим правилом было бы "если сомневаешься, избегай его". Но экранирование некоторых символов придает им особое значение, например \n. Они перечислены на страницах man bash в Quoting и echo.

Кроме этого, избегайте любого символа, который не является буквенно-цифровым, это безопаснее. Я не знаю ни одного окончательного списка.

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

Тот, кто поймал меня, это !. Это специальный символ (расширение истории) в Bash (и csh), но не в Korn Shell. Даже echo "Hello world!" дает проблемы. Использование одинарных кавычек, как обычно, удаляет особое значение.

18
cdarke

Я предполагаю, что вы говорите о струнах bash. Существуют разные типы строк, которые имеют разные требования к экранированию. например. Строки в одинарных кавычках отличаются от строк в двойных кавычках.

Лучшая ссылка - раздел цитирование руководства по bash.

Это объясняет, каких персонажей нужно убежать. Обратите внимание, что некоторым символам может потребоваться экранирование в зависимости от того, какие опции включены, например, расширение истории.

4
Austin Phillips

Я заметил, что bash автоматически экранирует некоторые символы при использовании автозаполнения.

Например, если у вас есть каталог с именем dir:A, bash автоматически завершит работу до dir\:A

Используя это, я провел несколько экспериментов с использованием символов таблицы ASCII и ​​вывел следующие списки:

символы, которые bash экранирует при автозаполнении: (включает пробел)

 !"$&'()*,:;<=>[email protected][\]^`{|}

символы, которые bash не покидает:

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

(Я исключил /, поскольку его нельзя использовать в именах каталогов)

3
yuri