Как экранировать одиночные кавычки внутри строк, заключённых в одиночные кавычки
У меня есть проблема с определением alias в Bash. Вот простой пример, который работает без проблем:
alias rxvt='urxvt'
Однако, когда я пытаюсь установить alias с параметрами, это не срабатывает:
alias rxvt='urxvt -fg '#111111' -bg '#111111''
Аналогично, следующий вариант тоже не работает:
alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''
Таким образом, у меня возник вопрос: как правильно сопоставить открывающие и закрывающие кавычки внутри строки, когда нужно использовать экранирование? Вариант:
alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
выглядит довольно громоздко, хотя, по сути, он передает ту же строку, если интерпретация опять же допускает конкатенацию таким образом. Как можно решить эту проблему более элегантно?
5 ответ(ов)
Если вам действительно нужно использовать одинарные кавычки на внешнем уровне, помните, что вы можете комбинировать разные виды кавычек. Пример:
alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
# ^^^^^ ^^^^^ ^^^^^ ^^^^
# 12345 12345 12345 1234
Объяснение того, как '"'"'
интерпретируется как просто '
:
'
Закрывает первую кавычку, использующую одинарные кавычки."
Открывает вторую кавычку, использующую двойные кавычки.'
Символ в кавычках."
Закрывает вторую кавычку, использующую двойные кавычки.'
Открывает третью кавычку, использующую одинарные кавычки.
Если вы не вставите пробелы между (1) и (2) или между (4) и (5), оболочка интерпретирует эту строку как одно длинное слово:
$ echo 'abc''123'
abc123
$ echo 'abc'\''123'
abc'123
$ echo 'abc'"'"'123'
abc'123
Оболочка также сохранит внутреннее представление с "соединяемыми" строками и предпочтёт более короткий синтаксис экранирования, когда это возможно:
$ alias test='echo '"'"'hi'"'"
$ alias test
alias test='echo '\''hi'\'''
$ test
hi
Кратко
Я всегда заменяю каждую вложенную одинарную кавычку на последовательность: '\''
(т.е. кавычка, обратный слэш, кавычка, кавычка), что позволяет закрыть строку, добавить экранированную одинарную кавычку и снова открыть строку.
Более подробно о преобразовании строк с вложенными одинарными кавычками
Часто я создаю функцию "quotify" в своих скриптах на Perl, чтобы сделать это за меня. Этапы будут следующими:
s/'/'\\''/g # Обработка каждой вложенной кавычки
$_ = qq['$_']; # Обрамление результата одинарными кавычками.
Это в целом позволяет решить все случаи.
Жизнь становится более интересной, когда вы вводите eval
в свои shell-скрипты. Вам фактически придется снова переупаковать (quotify) все!
Например, создайте скрипт на Perl с именем quotify, содержащий приведенные выше строки:
#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];
Затем используйте его для генерации правильно закомментированной строки:
$ quotify
urxvt -fg '#111111' -bg '#111111'
Результат:
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Эту строку затем можно вставить в команду alias:
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
(Если вам нужно вставить команду в eval, снова выполните quotify:
$ quotify
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Результат:
'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
Эту строку можно скопировать и вставить в eval:
eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
Я могу подтвердить, что использование '\''
для одиночной кавычки внутри строки, заключенной в одинарные кавычки, действительно работает в Bash, и это можно объяснить аналогично аргументу "слияния" из предыдущих ответов. Предположим, у нас есть строка, заключенная в кавычки: 'A '\''B'\'' C'
(все кавычки здесь одинарные). Если передать эту строку команде echo, она выведет: A 'B' C
.
В каждом '\''
первая кавычка закрывает текущую строку, заключенную в одинарные кавычки, следующий \'
"сшивает" одиночную кавычку с предыдущей строкой (то есть \'
— это способ указать одиночную кавычку без начала новой строки), а последняя кавычка открывает новую строку, заключенную в одинарные кавычки.
Вот простой пример экранирования кавычек в оболочке (shell):
$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc
Это осуществляется с помощью завершения уже открытой кавычки ('
), вставки экранированной кавычки (\'
), а затем повторного открытия кавычки ('
). Такая синтаксическая конструкция работает для всех команд. Это очень похоже на первый ответ.
Я не конкретно касаюсь проблемы с кавычками, потому что иногда просто разумно рассмотреть альтернативный подход.
rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }
После чего вы можете вызвать это следующим образом:
rxvt 123456 654321
Идея в том, что теперь вы можете сделать алиас, не беспокоясь о кавычках:
alias rxvt='rxvt 123456 654321'
Или, если вам нужно включить #
во всех вызовах по какой-то причине:
rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }
Тогда вы сможете вызвать его так:
rxvt '#123456' '#654321'
И, конечно, алиас будет выглядеть так:
alias rxvt="rxvt '#123456' '#654321'"
(Ой, судя по всему, я всё-таки немного затронул тему кавычек 😃 )
Как объединить строковые переменные в Bash
Когда нужны фигурные скобки вокруг переменных в оболочке?
Преимущественны ли двойные квадратные скобки [[ ]] над одинарными [ ] в Bash?
Извлечение имени файла и расширения в Bash
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?