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

есть ли полный список символов, которые должны быть экранированы в Bash? Можно ли проверить только с помощью sed?

в частности, я проверял, есть ли % должен быть экранирован или нет. Я пытался!--8-->

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

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

и более общие: они же символы, чтобы избежать в shell и bash?

7 ответов


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

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

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

'I'\''m a s@fe $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\ s@fe\ $tring\ which\ ends\ in\ newline"
"

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


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

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


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


чтобы спасти кого-то еще от необходимости RTFM... в Баш:

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

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

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


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

есть специальные printf директива формат (%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 $'2'    34 - 4          4E - N          68 - h      
01 E $'1'    1B E $'\E'      35 - 5          4F - O          69 - i      
02 E $'2'    1C E $'4'    36 - 6          50 - P          6A - j      
03 E $'3'    1D E $'5'    37 - 7          51 - Q          6B - k      
04 E $'4'    1E E $'6'    38 - 8          52 - R          6C - l      
05 E $'5'    1F E $'7'    39 - 9          53 - S          6D - m      
06 E $'6'    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 $'6'    28 E \(         42 - B          5C E \         76 - v      
0F E $'7'    29 E \)         43 - C          5D E \]         77 - w      
10 E $'0'    2A E \*         44 - D          5E E \^         78 - x      
11 E $'1'    2B - +          45 - E          5F - _          79 - y      
12 E $'2'    2C E \,         46 - F          60 E \`         7A - z      
13 E $'3'    2D - -          47 - G          61 - a          7B E \{     
14 E $'4'    2E - .          48 - H          62 - b          7C E \|     
15 E $'5'    2F - /          49 - I          63 - c          7D E \}     
16 E $'6'    30 - 0          4A - J          64 - d          7E E \~     
17 E $'7'    31 - 1          4B - K          65 - e          7F E $'7'
18 E $'0'    32 - 2          4C - L          66 - f      
19 E $'1'    33 - 3          4D - M          67 - g      

где первое поле-Значение hexa байта, второе содержит 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 

символы, которые нуждаются в экранировании, отличаются в оболочке Bourne или POSIX от Bash. Вообще (очень) Bash-это надмножество этих оболочек, поэтому все, что вы избегаете в shell должен быть экранирован в Bash.

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

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

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

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


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

#!/bin/bash
special=$'`!@#$%^&*()-_+={}|[]\;\':",.<>?/ '
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 в это.


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

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

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


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

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

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

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

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

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

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

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