Как избежать одинарных кавычек внутри одинарных строк? - PullRequest
866 голосов
/ 09 августа 2009

Допустим, у вас есть bash alias вроде:

alias rxvt='urxvt'

который отлично работает.

Тем не менее:

alias rxvt='urxvt -fg '#111111' -bg '#111111''

не будет работать и не будет:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

Так как же вы в конечном итоге сопоставляете открывающие и закрывающие кавычки внутри строки после того, как вы избежали кавычек?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

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

Ответы [ 20 ]

1255 голосов
/ 09 августа 2009

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

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

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

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

Если вы не ставите пробелы между (1) и (2) или между (4) и (5), оболочка интерпретирует эту строку как одно длинное слово.

230 голосов
/ 22 августа 2009

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


Я часто запускаю функцию «quotify» в моих скриптах Perl, чтобы сделать это для меня. Шаги будут:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

Это в значительной степени заботится обо всех случаях.

Жизнь становится веселее, когда вы вводите eval в свои shell-скрипты. Вы, по сути, должны заново оценить все заново!

Например, создайте сценарий Perl с именем quotify, содержащий приведенные выше операторы:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

затем используйте его для генерации строки в правильных кавычках:

$ quotify
urxvt -fg '#111111' -bg '#111111'

результат:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

, который затем можно скопировать / вставить в команду псевдонима:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(Если вам нужно вставить команду в eval, запустите цитату еще раз:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

результат:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

, который можно скопировать / вставить в eval:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
153 голосов
/ 17 мая 2013

Поскольку синтаксис Bash 2.04 $'string' (вместо просто 'string'; предупреждение: не путайте с $('string')) - это еще один механизм цитирования, который допускает ANSI C-подобные escape-последовательности и выполнить расширение до версии в одинарных кавычках.

Простой пример:

  $> echo $'aa\'bb'
  aa'bb

  $> alias myvar=$'aa\'bb'
  $> alias myvar
  alias myvar='aa'\''bb'

В вашем случае:

$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

Обычные экранирующие последовательности работают как положено:

\'     single quote
\"     double quote
\\     backslash
\n     new line
\t     horizontal tab
\r     carriage return

Ниже приведена копия + вставлена ​​соответствующая документация man bash (версия 4.4):

Слова вида $ 'string' обрабатываются специально. Слово расширяется до строки, символы с обратной косой чертой заменяются в соответствии со стандартом ANSI C. Escape-последовательности с обратной косой чертой, если они есть, декодируются следующим образом:

    \a     alert (bell)
    \b     backspace
    \e
    \E     an escape character
    \f     form feed
    \n     new line
    \r     carriage return
    \t     horizontal tab
    \v     vertical tab
    \\     backslash
    \'     single quote
    \"     double quote
    \?     question mark
    \nnn   the eight-bit character whose value is the octal 
           value nnn (one to three digits)
    \xHH   the eight-bit character whose value is the hexadecimal
           value HH (one or two hex digits)
    \uHHHH the Unicode (ISO/IEC 10646) character whose value is 
           the hexadecimal value HHHH (one to four hex digits)
    \UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value 
               is the hexadecimal value HHHHHHHH (one to eight 
               hex digits)
    \cx    a control-x character

Расширенный результат заключен в одинарные кавычки, как если бы знак доллара отсутствовал.


См. Цитаты и экранирование: ANSI C как строки на вики bash-hackers.org для получения более подробной информации. Также обратите внимание, что «Bash Changes» файл ( обзор здесь ) много упоминает об изменениях и исправлениях ошибок, связанных с механизмом цитирования $'string'.

Согласно unix.stackexchange.com Как использовать специальный символ в качестве нормального? он должен работать (с некоторыми вариациями) в bash, zsh, mksh, ksh93 и FreeBSD и busybox sh.

48 голосов
/ 09 августа 2009

Я не вижу записи в его блоге (ссылка, пожалуйста?), Но согласно справочному руководству GNU :

Заключение символов в одинарные кавычки (‘'’) Сохраняет буквальное значение каждый символ в кавычках. одиночная кавычка может не встречаться одинарные кавычки, даже если им предшествует обратная косая черта.

так что bash не поймет:

alias x='y \'z '

однако вы можете сделать это, если заключите в двойные кавычки:

alias x="echo \'y "
> x
> 'y
27 голосов
/ 03 августа 2011

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

15 голосов
/ 28 февраля 2015

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

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

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

15 голосов
/ 20 февраля 2015

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

Автор вопроса не заметил, что в конце его последней попытки побега была добавлена ​​одиночная кавычка ('):

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           │         │┊┊|       │┊┊│     │┊┊│       │┊┊│
           └─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      └┴─────────┴┴───┰───┴┴─────────┴┘│
                          All escaped single quotes    │
                                                       │
                                                       ?

Как вы можете видеть в предыдущем прекрасном кусочке ASCII / Unicode, за последней экранированной одинарной кавычкой (\ ') следует ненужная одинарная кавычка ('). Использование подсветки синтаксиса, подобной тому, что представлен в Notepad ++, может оказаться очень полезным.

То же самое относится и к другому примеру, подобному следующему:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

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

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214
12 голосов
/ 22 августа 2009

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

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

(упс, я думаю, я вроде как обратился к цитате :)

10 голосов
/ 16 декабря 2014

Я просто использую шелл-коды .. например \x27 или \\x22 в зависимости от обстоятельств. Никаких хлопот, правда.

9 голосов
/ 12 февраля 2016

Поскольку нельзя заключать одинарные кавычки в строки одинарных кавычек, самый простой и читаемый вариант - использовать строку HEREDOC

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

В приведенном выше коде HEREDOC отправляется команде cat, а ее выход присваивается переменной через запись подстановки команды $(..)

Необходимо поставить одинарную кавычку вокруг HEREDOC, поскольку она находится в пределах $()

...