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

91
голос

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

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

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

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

И более общие: являются ли они одинаковыми символами для выхода в shell и bash?

задан fedorqui 03 апр. '13 в 12:32
источник

7 ответов

118
голосов

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

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

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

'I'\''m a s@fe $tring which ends in newline
'

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

2. Побег каждого char с обратным слэшем

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

\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. Обработка двоичных данных не определена. Для реализаций, которые имеют значение, бинарные работы, за исключением NUL байтов (поскольку переменные реализованы с помощью строк C и предназначены для использования как строки C, а именно аргументы программы), но вы должны переключиться на "двоичную" локаль, такую ​​как latin1.


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

ответ дан Jo So 18 нояб. '13 в 19:47
источник
19
голосов

Чтобы спасти кого-то еще от RTFM... в bash:

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

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

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

ответ дан Matthew 04 марта '14 в 2:00
источник
16
голосов

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

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

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

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

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

ответ дан cdarke 03 апр. '13 в 12:53
источник
13
голосов

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

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

printf [-v var] format [arguments]

 %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'
ответ дан F. Hauri 07 янв. '15 в 13:38
источник
3
голосов

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

Лучшей ссылкой является Quoting раздел руководства bash.

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

ответ дан Austin Phillips 03 апр. '13 в 12:54
источник
3
голосов

Используя метод 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 на этом.

ответ дан codeforester 16 июня '17 в 7:52
источник
3
голосов

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

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

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

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

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

Символы, которые bash не исчезают:

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

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

ответ дан yuri 30 янв. '16 в 5:58
источник

Другие вопросы по меткам