14

Как экранировать одиночные кавычки внутри строк, заключённых в одиночные кавычки

11

У меня есть проблема с определением 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 ответ(ов)

19

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

alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
#                     ^^^^^       ^^^^^     ^^^^^       ^^^^
#                     12345       12345     12345       1234

Объяснение того, как '"'"' интерпретируется как просто ':

  1. ' Закрывает первую кавычку, использующую одинарные кавычки.
  2. " Открывает вторую кавычку, использующую двойные кавычки.
  3. ' Символ в кавычках.
  4. " Закрывает вторую кавычку, использующую двойные кавычки.
  5. ' Открывает третью кавычку, использующую одинарные кавычки.

Если вы не вставите пробелы между (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
3

Кратко

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

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

Часто я создаю функцию "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'\''\'\'''\'''\'''
0

Я могу подтвердить, что использование '\'' для одиночной кавычки внутри строки, заключенной в одинарные кавычки, действительно работает в Bash, и это можно объяснить аналогично аргументу "слияния" из предыдущих ответов. Предположим, у нас есть строка, заключенная в кавычки: 'A '\''B'\'' C' (все кавычки здесь одинарные). Если передать эту строку команде echo, она выведет: A 'B' C.

В каждом '\'' первая кавычка закрывает текущую строку, заключенную в одинарные кавычки, следующий \' "сшивает" одиночную кавычку с предыдущей строкой (то есть \' — это способ указать одиночную кавычку без начала новой строки), а последняя кавычка открывает новую строку, заключенную в одинарные кавычки.

0

Вот простой пример экранирования кавычек в оболочке (shell):

$ echo 'abc'\''abc'
abc'abc

$ echo "abc"\""abc"
abc"abc

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

0

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

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'"

(Ой, судя по всему, я всё-таки немного затронул тему кавычек 😃 )

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь