Как избежать одинарных кавычек в одинарных кавычках

Допустим, у вас есть 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'\''

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


person cons    schedule 08.08.2009    source источник
comment
Вы понимаете, что вам не нужно использовать одинарные кавычки для псевдонима? Двойные кавычки намного проще.   -  person teknopaul    schedule 10.01.2016
comment
См. Также: Разница между одинарными и двойными кавычками в Bash.   -  person codeforester    schedule 02.06.2017
comment
Вложенные двойные кавычки можно экранировать, "\"", поэтому их следует использовать, когда это возможно, вместо ответа @ liori.   -  person alan    schedule 20.10.2017
comment
Двойные кавычки ведут себя совершенно иначе, чем одинарные кавычки в * nix (включая Bash и связанные инструменты, такие как Perl), поэтому замена двойных кавычек всякий раз, когда возникает проблема с одинарными кавычками, НЕ является хорошим решением. Двойные кавычки указывают, что переменные $ ... должны быть заменены перед выполнением, а одинарные кавычки указывают, что $ ... должны обрабатываться буквально.   -  person Chuck Kollars    schedule 28.05.2019
comment
Если вы думаете: Я использовал двойные кавычки, но это все еще не работает, снова создайте свой скрипт.   -  person Samy Bencherif    schedule 09.07.2019
comment
Последняя попытка была близка, просто удалите последнюю цитату.   -  person bac0n    schedule 09.05.2021


Ответы (24)


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

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

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

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

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

person liori    schedule 09.08.2009
comment
alias splitpath='echo $PATH | awk -F : '"'"'{print "PATH is set to"} {for (i=1;i<=NF;i++) {print "["i"]",$i}}'"'" Работает, когда в строке псевдонима есть как одинарные, так и двойные кавычки! - person Uphill_ What '1; 01.06.2011
comment
Моя интерпретация: bash неявно объединяет строковые выражения в различных кавычках. - person Benjamin Atkin; 14.08.2013
comment
работал у меня, пример двойных экранированных одинарных кавычек: alias serve_this_dir='ruby -rrack -e "include Rack;Handler::Thin.run Builder.new{run Directory.new'"'"''"'"'}"' - person JAMESSTONEco; 13.09.2013
comment
Уж точно не самое читабельное решение. Он чрезмерно использует одинарные кавычки там, где они на самом деле не нужны. - person oberlies; 25.11.2013
comment
Это хорошее решение, поскольку оно позволяет избежать сложной проблемы, связанной с переработкой кавычек для команды, которая требует размышлений. Это решение требует простого перевода. Если бы только в bash были макросы, вы могли бы это реализовать. - person Pyrolistical; 12.02.2014
comment
Работает ли это, когда вы меняете местами двойные и одинарные кавычки? т.е. "urxvt -fg "'"'"#111111"'"'" и т. д.? Кажется, у меня не работает, но может я что-то делаю не так. - person 2rs2ts; 08.05.2014
comment
@ 2rs2ts: должно работать. Если нет - задайте новый вопрос здесь, на сайте. - person liori; 08.05.2014
comment
Отлично! У меня возникли проблемы с псевдонимом в .bash_aliases, который я сделал, как вы предлагаете, а затем выдал псевдоним в CLI, выводит ... awk '\''{print $3}'\'' '', т.е. он также действителен \' вместо "'" вне строки одинарной кавычки. - person juanmf; 16.06.2014
comment
@ rs2ts Оставьте последнюю двойную кавычку. echo "it "'"'"works"'"' - person Chad Skeeters; 09.07.2014
comment
TL; DR заменить каждый внутренний ' на '\'' command = "echo '" + arg.replace("'", "'\\''") + "'"; exec(command) - person karmakaze; 22.08.2014
comment
Отличный ответ по содержанию. Но было бы легче понять, если бы можно было объединить символом вроде + - это невозможно (afaik), но пример, показывающий, как это выглядит, мог бы помочь другим осознать One True Way (этот пример не работает, это чтобы помочь понять, что происходит): alias rxvt='urxvt -fg '+"'"+'#111111'+"'"+' -bg '+"'"+'#111111'+"'" - person Steve Midgley; 12.09.2014
comment
Для тех, кому просто нужно решение (где double - нормально): псевдоним rxvt = urxvt -fg '# 111111' -bg '# 111111' - person cmroanirgo; 18.01.2015
comment
для тех из вас, кто ДЕЙСТВИТЕЛЬНО хочет ответа, лол ... просто используйте '"'"'. и если вы хотите избежать ЭТИ одинарных кавычек, используйте '\"'\"' LOL - person Alex Gray; 16.08.2015
comment
Это неправильные одинарные кавычки во внешнем слое - это не то, что достигается, вы объединяете строки, используя разные типы escape. Нет внешнего слоя. - person teknopaul; 10.01.2016
comment
Я утверждаю, что '\'' гораздо удобнее читать в большинстве контекстов, чем '"'"'. Фактически, первое почти всегда четко различается в пределах строки, заключенной в одинарные кавычки, и, таким образом, это просто вопрос его семантического сопоставления со значением экранированной кавычки, как это делается с \" в строках с двойными кавычками. В то время как последний сливается в одну строку цитат, и во многих случаях требует тщательного изучения, чтобы правильно различить. - person mtraceur; 06.09.2016
comment
Другой пример использования: awk '{print "'"'"'"$2"'"'"' => '"'"'"$3"'"'"'"}' выводит строку, например: 'value$2' => 'value$3' - person Ligemer; 24.11.2016
comment
Таким же образом можно избежать двойных кавычек; просто поменяйте местами двойные и одинарные кавычки в '"'"' - person Amil Waduwawara; 11.12.2017
comment
LOL, использование двойных кавычек - обман. :) Тогда вы можете просто использовать двойные кавычки снаружи для простейшего решения, основанного на здравом смысле. Реальное решение, использующее только одинарные кавычки, - stackoverflow.com/a/49063038 - person wisbucky; 02.03.2018
comment
@liori, это классный трюк. Спасибо! Теперь я могу использовать одинарные кавычки внутри perl on-liners! демо: perl -le '$q = chr(39); $_=shift; s/$q/$q"$q"$q/g; print qq[echo $q$_$q]' "It's amazing" дает: echo 'It'"'"'s amazing' Я добавил его в свою кулинарную книгу рецептов! - person stason; 30.06.2018
comment
Из представленных ниже вариантов это единственный, который работает в моей ситуации: alias kernel_ext='kextstat -kl | awk '"'"'!/com\.apple/{printf "%s %s\n", $6, $7}'"'" - person Jonathan Cross; 19.07.2018
comment
это ЕДИНСТВЕННЫЙ способ сделать grep псевдоним для правильной работы! - person João Ciocca; 22.05.2020
comment
вау, спасибо. меня устраивает. - person Jacky Supit; 18.01.2021

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


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

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

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

Жизнь становится веселее, когда вы вводите eval в свои сценарии оболочки. По сути, вам придется заново все переквалифицировать!

Например, создайте сценарий 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'\''\'\'''\'''\'''
person Adrian Pronk    schedule 22.08.2009
comment
Но это не Perl. И как Стив Б. указал выше, ссылаясь на справочное руководство по gnu, вы не можете избежать кавычек в bash внутри одного и того же типа цитат. И на самом деле не нужно экранировать их в альтернативных кавычках, например. '- допустимая строка в одинарных кавычках, а' '- допустимая строка в двойных кавычках без необходимости экранирования. - person nicerobot; 22.08.2009
comment
@nicerobot: я добавил пример, показывающий, что: 1) я не пытаюсь экранировать кавычки в одном типе цитат, 2) ни в альтернативных кавычках, и 3) Perl используется для автоматизации процесса создания действительных кавычек. строка bash, содержащая встроенные кавычки - person Adrian Pronk; 12.05.2013
comment
Первый абзац сам по себе - это ответ, который я искал. - person Dave Causey; 04.03.2016
comment
То же самое делает и bash: введите set -x и echo "here's a string", и вы увидите, что bash выполняет echo 'here'\''s a string'. (set +x для возврата к нормальному поведению) - person arekolek; 07.08.2016

Поскольку 2.04 в Bash синтаксис $'string' допускает ограниченный набор экранирований.

Начиная с Bash 4.4, $'string' также позволяет использовать полный набор экранирования в стиле C, что делает поведение немного отличается в $'string' в предыдущих версиях. (Ранее можно было использовать форму $('string').)

Простой пример в Bash 2.04 и новее:

  $> 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):

Особо обрабатываются слова вида $ 'строка'. Слово заменяется строкой с заменой экранированных символов обратной косой черты в соответствии со стандартом ANSI C. Управляющие последовательности с обратной косой чертой, если они есть, декодируются следующим образом:

    \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 wiki Больше подробностей. Также обратите внимание, что файл Bash Changes (< href = "http://wiki.bash-hackers.org/scripting/bashchanges" rel = "nofollow noreferrer"> обзор здесь) много упоминает об изменениях и исправлениях ошибок, связанных с $'string' механизмом цитирования.

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

person Community    schedule 17.05.2013
comment
можно использовать, но строка в одинарных кавычках здесь не является реальной строкой в ​​одиночных кавычках, содержимое этой строки может быть вставлено оболочкой: _1 _ = ›!ar': event not found - person regilero; 28.05.2014
comment
На моей машине > echo $BASH_VERSION 4.2.47(1)-release > echo $'foo\'b!ar' foo'b!ar - person mj41; 09.06.2014
comment
Да, это причина может, у меня он был на Red Hat 6.4, конечно, более старой версии bash. - person regilero; 09.06.2014
comment
Bash ChangeLog содержит множество исправлений ошибок, связанных с $', поэтому, вероятно, самый простой способ - чтобы попробовать это на старых системах. - person mj41; 14.06.2014
comment
имейте в виду: e. Bash no longer inhibits C-style escape processing ($'...') while performing pattern substitution word expansions. Взято из tiswww.case.edu/php/chet/bash/CHANGES < / а>. Все еще работает в 4.3.42, но не в 4.3.48. - person stiller_leser; 12.07.2018

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

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

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

alias x='y \'z '

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

alias x="echo \'y "
> x
> 'y
person Steve B.    schedule 08.08.2009
comment
comment
Содержимое, заключенное в двойные кавычки, оценивается, поэтому заключение только одинарных кавычек в двойные кавычки, как предлагает liori, кажется правильным решением. - person Piotr Dobrogost; 16.11.2012
comment
Это реальный ответ на вопрос. Хотя принятый ответ может дать решение, технически он отвечает на вопрос, который не был задан. - person Matthew G; 14.05.2015
comment
Мэтью, вопрос заключался в том, чтобы избежать одинарных кавычек внутри одинарных кавычек. Этот ответ просит пользователя изменить свое поведение, и если у вас есть препятствие для использования двойных кавычек (как следует из названия вопроса), этот ответ не поможет. Тем не менее, это довольно полезно (хотя и очевидно) и, как таковое, заслуживает одобрения, но принятый ответ касается точной проблемы, о которой спрашивал Op. - person Fernando Cordeiro; 10.07.2015
comment
Не нужно заключать одинарные кавычки в строку с двойными кавычками. - person Matthew D. Scholefield; 19.07.2018

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

person Mikhail at YugaByte    schedule 03.08.2011
comment
Это вводит в заблуждение, этот синтаксис '\' 'не входит в одну строку в кавычках. В этом заявлении 'A' \ '' B '\' 'C' вы объединяете строки 5 \ escape и одинарные кавычки - person teknopaul; 10.01.2016
comment
@teknopaul Присваивание alias something='A '\''B'\'' C' действительно приводит к тому, что something является единственной строкой, поэтому даже если правая часть присваивания технически не является единственной строкой, я не думаю, что это имеет большое значение. - person Teemu Leisti; 07.09.2016
comment
Хотя это работает в вашем примере, это не технически решение того, как вставить одинарную кавычку внутри строки в одиночных кавычках. Вы уже объяснили это, но да, это работает 'A ' + ' + 'B' + ' + ' C'. Другими словами, решение для вставки символов одинарных кавычек внутри строки, заключенной в одинарные кавычки, должно позволить мне создать такую ​​строку отдельно и распечатать ее. Однако в этом случае это решение не сработает. STR='\''; echo $STR. В соответствии с задумкой BASH на самом деле не позволяет этого. - person krb686; 14.09.2016
comment
@mikhail_b, да, '\'' на баш работает. Не могли бы вы указать, какие разделы gnu.org/software/bash/manual/bashref .html указать такое поведение? - person Jingguo Yao; 16.09.2016

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

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

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
person Community    schedule 20.02.2015
comment
Upwoted для иллюстрации таблицы ASCII :) - person php-dev; 13.07.2015
comment
Как вы создали этот юникод? Это прекрасно! - person Quelklef; 08.01.2021

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

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

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

person kenorb    schedule 28.02.2015

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

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

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

person nicerobot    schedule 22.08.2009
comment
Я пытался заключить что-то в одинарные кавычки, которые были в двойных кавычках, которые, в свою очередь, были в одинарных кавычках. Ой. Спасибо за ваш ответ и попробуйте другой подход. Это имело значение. - person Clinton Blackmore; 28.04.2010
comment
Я опоздал на 5 лет, но разве вы не пропустили ни одной цитаты в своем последнем псевдониме? - person Julien; 19.01.2017
comment
@Julien, я не вижу проблемы ;-) - person nicerobot; 20.01.2017

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

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

alias rxvt=$command

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

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

person Abbas Gadhia    schedule 12.02.2016
comment
Хотел бы я прокручивать так далеко раньше - я заново изобрел этот подход и пришел сюда, чтобы опубликовать его! Это намного чище и читабельнее, чем все другие подходы к экранированию. Нет, это не будет работать с некоторыми оболочками, отличными от bash, такими как dash, который является оболочкой по умолчанию в сценариях выскочки Ubuntu и в других местах. - person Korny; 10.08.2017
comment
Спасибо! то, что я искал, способ определить команду как есть через heredoc и передать команду с автоматическим экранированием в ssh. BTW cat ‹< КОМАНДА без кавычек позволяет интерполировать переменные внутри команды и также работает для этого подхода. - person Igor Tverdovskiy; 18.05.2020

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

person Rob Jens    schedule 16.12.2014
comment
Не могли бы вы показать пример этого в действии? Для меня он просто печатает буквальный x27 (на Centos 6.6) - person Will Sheppard; 28.03.2018
comment
@WillSheppard echo -e "\x27 \\x22" печатает ' " - person Marcos; 16.06.2020
comment
@WillSheppard и другие, вот несколько примеров того, что я только что написал: stackoverflow.com/a/65878993/4561887 . - person Gabriel Staples; 25.01.2021

ИМХО настоящий ответ заключается в том, что вы не можете избежать одинарных кавычек в одинарных кавычках.

Это невозможно.

Если предположить, что мы используем bash.

Из руководства bash ...

Enclosing characters in single quotes preserves the literal value of each
character within the quotes.  A single quote may not occur
between single quotes, even when preceded by a backslash.

Вам нужно использовать один из других механизмов выхода строки "или \

В alias нет ничего волшебного, требующего использования одинарных кавычек.

Оба следующих варианта работают в bash.

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

Последний использует \ для экранирования символа пробела.

Также нет ничего волшебного в # 111111, требующем одинарных кавычек.

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

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

Вы также можете избежать проблемного # напрямую

alias rxvt="urxvt -fg \#111111 -bg \#111111"
person teknopaul    schedule 09.01.2016
comment
настоящий ответ заключается в том, что вы не можете избежать одинарных кавычек в одинарных кавычках. Технически это правда. Но у вас может быть решение, которое начинается с одинарной кавычки, заканчивается одинарной кавычкой и содержит только одинарные кавычки в середине. stackoverflow.com/a/49063038 - person wisbucky; 02.03.2018
comment
Не путем побега, а только путем конкатенации. - person teknopaul; 03.03.2018

Большинство этих ответов касаются конкретного случая, о котором вы спрашиваете. Существует общий подход, который разработали мы с другом, который позволяет использовать произвольные кавычки в случае, если вам нужно цитировать команды bash через несколько уровней расширения оболочки, например, через ssh, su -c, bash -c и т. Д. Вам нужен один базовый примитив. , здесь в родном bash:

quote_args() {
    local sq="'"
    local dq='"'
    local space=""
    local arg
    for arg; do
        echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
        space=" "
    done
}

Это делает именно то, что он говорит: он заключает в кавычки каждый аргумент индивидуально (после расширения bash, конечно):

$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'

Это очевидная вещь для одного уровня расширения:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(Обратите внимание, что двойные кавычки вокруг $(quote_args ...) необходимы, чтобы преобразовать результат в единственный аргумент для bash -c.) И его можно использовать в более общем плане для правильного цитирования через несколько уровней раскрытия:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

Приведенный выше пример:

  1. оболочка заключает в кавычки каждый аргумент внутреннего quote_args по отдельности, а затем объединяет результирующий вывод в один аргумент с внутренними двойными кавычками.
  2. shell-кавычки bash, -c и уже однажды заключенный в кавычки результат шага 1, а затем объединяет результат в один аргумент с внешними двойными кавычками.
  3. отправляет этот беспорядок в качестве аргумента внешнему bash -c.

Это вкратце идея. Вы можете делать с этим довольно сложные вещи, но вы должны быть осторожны с порядком оценки и с тем, какие подстроки цитируются. Например, следующие действия делают неправильные вещи (для некоторого определения «неправильного»):

$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure

В первом примере bash немедленно расширяет quote_args cd /; pwd 1>&2 на две отдельные команды, quote_args cd / и pwd 1>&2, так что CWD по-прежнему /tmp, когда выполняется команда pwd. Второй пример иллюстрирует аналогичную проблему для подстановки. Действительно, та же самая основная проблема возникает со всеми расширениями bash. Проблема здесь в том, что подстановка команды не является вызовом функции: она буквально оценивает один сценарий bash и использует его выходные данные как часть другого сценария bash.

Если вы попытаетесь просто избежать операторов оболочки, вы потерпите неудачу, потому что результирующая строка, переданная в bash -c, представляет собой просто последовательность строк, заключенных в индивидуальные кавычки, которые затем не интерпретируются как операторы, что легко увидеть, если вы повторите строку, которая было бы передано в bash:

$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'

Проблема здесь в том, что вы цитируете слишком много. Вам нужно, чтобы операторы не заключались в кавычки в качестве входных данных для включающего bash -c, что означает, что они должны находиться вне подстановки команд $(quote_args ...).

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

$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success

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

$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success

и т.п.

Эти примеры могут показаться излишними, учитывая, что такие слова, как success, sbin и pwd не нужно заключать в кавычки, но ключевой момент, который следует помнить при написании сценария с произвольным вводом, заключается в том, что вы хотите цитировать все, что вы не совсем конечно, не нуждается в цитировании, потому что вы никогда не знаете, когда пользователь вставит Robert'; rm -rf /.

Чтобы лучше понять, что происходит под обложками, вы можете поиграть с двумя небольшими вспомогательными функциями:

debug_args() {
    for (( I=1; $I <= $#; I++ )); do
        echo -n "$I:<${!I}> " 1>&2
    done
    echo 1>&2
}

debug_args_and_run() {
    debug_args "$@"
    "$@"
}

который перечислит каждый аргумент команды перед ее выполнением:

$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2
person Kyle Rose    schedule 29.12.2015
comment
Привет, Кайл. Ваше решение отлично сработало для моего случая, когда мне нужно было передать группу аргументов как один аргумент: vagrant ssh -c {single-arg} guest. {single-arg} нужно рассматривать как один аргумент, потому что vagrant принимает следующий за ним аргумент в качестве имени гостя. Порядок не может быть изменен. Но мне нужно было передать команду и ее аргументы в {single-arg}. Итак, я использовал ваш quote_args(), чтобы процитировать команду и ее аргументы, и заключил результат в двойные кавычки, и это сработало как шарм: vagrant ssh -c "'command' 'arg 1 with blanks' 'arg 2'" guest. Спасибо!!! - person Andreas Maier; 06.02.2016

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

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

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

В этом примере вы увидите, что двойных кавычек достаточно для защиты строки:

$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'
person oberlies    schedule 25.11.2013

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

$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'

Объяснение

Ключ в том, что вы можете закрыть одинарную кавычку и открывать ее повторно столько раз, сколько захотите. Например, foo='a''b' совпадает с foo='ab'. Таким образом, вы можете закрыть одинарную кавычку, добавить буквальную одинарную кавычку \', а затем снова открыть следующую одинарную кавычку.

Диаграмма разбивки

Эта диаграмма проясняет использование скобок, чтобы показать, где открываются и закрываются одинарные кавычки. Цитаты не «вложены», как круглые скобки. Также можно обратить внимание на цветовое мелирование, которое нанесено правильно. Строки в кавычках имеют темно-бордовый цвет, а \' - черный.

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'    # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^    # show open/close quotes
 urxvt -fg   ' #111111  '  -bg   ' #111111  '    # literal characters remaining

(По сути, это тот же ответ, что и у Адриана, но я чувствую, что это лучше объясняет. Также в его ответе есть две лишние одинарные кавычки в конце.)

person wisbucky    schedule 02.03.2018
comment
+1 за использование метода '\'' я рекомендую вместо метода '"'"', который людям часто труднее читать. - person mtraceur; 29.05.2020

Вот подробное описание «Единственного истинного ответа», упомянутого выше:

Иногда я загружаю с помощью rsync поверх ssh и мне нужно экранировать имя файла с помощью 'в нем ДВАЖДЫ! (OMG!) Один раз для bash и один раз для ssh. Здесь работает тот же принцип чередования разделителей кавычек.

Например, допустим, мы хотим получить: Истории Луи Теру в Лос-Анджелесе ...

  1. Сначала вы заключаете Луи Теру в одинарные кавычки для bash и двойные кавычки для ssh: '"Луи Теру"'
  2. Затем вы используете одинарные кавычки, чтобы избежать двойной кавычки '"'
  3. Используйте двойные кавычки, чтобы избежать апострофа "'"
  4. Затем повторите №2, используя одинарные кавычки, чтобы избежать двойной кавычки '"'
  5. Затем заключите LA Stories в одинарные кавычки для bash и двойные кавычки для ssh: '"LA Stories"'

И вот! Вы закончите с этим:

rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'

это ужасно много работы для одного маленького '' - но вот и все

person PatchyFog    schedule 07.04.2014

shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

Объяснение реализации:

  • двойные кавычки, чтобы мы могли легко выводить одинарные кавычки и использовать синтаксис ${...}

  • поиск и замена в bash выглядят так: ${varname//search/replacement}

  • мы заменяем ' на '\''

  • '\'' кодирует одиночный ' так:

    1. ' завершает одинарное цитирование

    2. \' кодирует ' (обратная косая черта необходима, потому что мы не внутри кавычек)

    3. ' снова запускает одинарное цитирование

    4. bash автоматически объединяет строки без пробелов между

  • перед каждыми \ и ' стоит \, потому что это правила экранирования для ${...//.../...}.

string="That's "'#@$*&^`(@#'
echo "original: $string"
echo "encoded:  $(shell_escape "$string")"
echo "expanded: $(bash -c "echo $(shell_escape "$string")")"

P.S. Всегда кодируйте строки в одинарных кавычках, потому что они намного проще, чем строки в двойных кавычках.

person JasonWoof    schedule 25.04.2019

Другой способ решить проблему слишком большого количества вложенных цитат:

Вы пытаетесь втиснуть слишком много в слишком маленькое пространство, поэтому используйте функцию bash.

Проблема в том, что вы пытаетесь иметь слишком много уровней вложенности, а базовая технология псевдонимов недостаточно мощна, чтобы ее приспособить. Используйте такую ​​функцию bash, чтобы сделать так, чтобы одинарные, двойные кавычки, обратные тики и переданные параметры обрабатывались нормально, как и следовало ожидать:

lets_do_some_stuff() {
    tmp=$1                       #keep a passed in parameter.
    run_your_program $@          #use all your passed parameters.
    echo -e '\n-------------'    #use your single quotes.
    echo `date`                  #use your back ticks.
    echo -e "\n-------------"    #use your double quotes.
}
alias foobarbaz=lets_do_some_stuff

Затем вы можете использовать свои переменные $ 1 и $ 2, а также одинарные, двойные кавычки и обратные тики, не беспокоясь о том, что функция псевдонима нарушит их целостность.

Эта программа печатает:

el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
person Eric Leschinski    schedule 27.10.2015

Если вы генерируете строку оболочки в Python 2 или Python 3, следующее может помочь заключить аргументы в кавычки:

#!/usr/bin/env python

from __future__ import print_function

try:  # py3
    from shlex import quote as shlex_quote
except ImportError:  # py2
    from pipes import quote as shlex_quote

s = """foo ain't "bad" so there!"""

print(s)
print(" ".join([shlex_quote(t) for t in s.split()]))

Это выведет:

foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'
person George V. Reilly    schedule 22.06.2017
comment
Спасибо, это просто отлично сработало для создания псевдонима, содержащего одинарные кавычки, обратную косую черту и знак доллара, без каких-либо ручных действий с моей стороны: print(shlex_quote(r"..<nasty string>...")) - person ojdo; 04.09.2020

Если у вас установлен GNU Parallel, вы можете использовать его внутренние кавычки:

$ parallel --shellquote
L's 12" record
<Ctrl-D>
'L'"'"'s 12" record'
$ echo 'L'"'"'s 12" record'
L's 12" record

Начиная с версии 20190222, вы можете даже --shellquote несколько раз:

$ parallel --shellquote --shellquote --shellquote
L's 12" record
<Ctrl-D>
'"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
$ eval eval echo '"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
L's 12" record

Он будет заключать строку в кавычки во всех поддерживаемых оболочках (не только bash).

person Ole Tange    schedule 11.07.2019

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

  • поместите это в quote.sh (или просто quote) где-нибудь на вашем PATH:
# this works with standard input (stdin)
quote() {
  echo -n "'" ;
  sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' ;
  echo -n "'"
}

case "$1" in
 -) quote ;;
 *) echo "usage: cat ... | quote - # single-quotes input for Bourne shell" 2>&1 ;;
esac

Пример:

$ echo -n "G'day, mate!" | ./quote.sh -
'G'"'"'day, mate!'

И, конечно же, обратное преобразование:

$ echo 'G'"'"'day, mate!'
G'day, mate!

Объяснение: в основном мы должны заключить ввод в кавычки ', а затем также заменить любую одиночную кавычку внутри этим микромонстром: '"'"' (закончить начальную цитату парой ', избежать найденной одиночной кавычки заключив его в двойные кавычки - "'", а затем, наконец, введите новую открывающую одинарную кавычку ' или в псевдонотации: ' + "'" + ' == '"'"')

Один из стандартных способов сделать это - использовать sed со следующей командой подстановки:

s/\(['][']*\)/'"\1"'/g 

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

sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' 

(и один из хороших способов добиться этого результата - передать исходное выражение s/\(['][']*\)/'"\1"'/g сценариям Кайла Роуза или Джорджа В. Рейли).

Наконец, имеет смысл ожидать, что ввод будет исходить от stdin - поскольку передача его через аргументы командной строки может быть уже слишком большой проблемой.

(О, и, возможно, мы захотим добавить небольшое справочное сообщение, чтобы сценарий не зависал, когда кто-то просто запускает его как ./quote.sh --help, недоумевая, что он делает.)

person ジョージ    schedule 31.01.2020

в дополнение к идеальному ответу @JasonWoof, я хочу показать, как я решил связанную проблему

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

#!/bin/bash

# no closing quote
string='alecxs\'solution'

# this works for string
string="alecxs'solution"
string=alecxs\'solution
string='alecxs'\''solution'

предположим, что строка - это имя файла, и нам нужно сохранить имена файлов в кавычках в списке (например, stat -c% N ./*> list)

echo "'$string'" > "$string"
cat "$string"

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

while read file
  do
    ls -l "$file"
    eval ls -l "$file"
done < "$string"

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

string="${string//$'\047'/\'\$\'\\\\047\'\'}"

# result
echo "$string"

теперь это работает, потому что котировки всегда сбалансированы

echo "'$string'" > list
while read file
  do
    ls -l "$file"
    eval ls -l "$file"
done < list

Надеюсь, это поможет при столкновении с подобной проблемой

person alecxs    schedule 14.06.2020
comment
используйте '$'\047'' или '$'\\047'' вместо '\'' в зависимости от оболочки - person alecxs; 14.06.2020

Как избежать одинарных кавычек (') и двойных кавычек (") с помощью шестнадцатеричных и восьмеричных символов

Если я использовал что-то вроде echo, у меня было несколько действительно сложных и действительно странных и труднодоступных (думаю: очень вложенных) случаев, когда единственное, что я мог заставить работать, - это использовать восьмеричные или шестнадцатеричные коды!

Вот некоторые примеры:

1. Пример одинарной кавычки, где ' экранирован с помощью шестнадцатеричного \x27 или восьмеричного \047 (соответствующий ему код ASCII):

# 1. hex
$ echo -e "Let\x27s get coding!"
Let's get coding!

# 2. octal
$ echo -e "Let\047s get coding!"
Let's get coding!

2. Пример двойной кавычки, где " экранирован с помощью шестнадцатеричного \x22 или восьмеричного \042 (соответствующий ему код ASCII).

Примечание: bash чокнутый! Иногда даже ! char имеет особое значение, и его необходимо удалить из двойных кавычек а затем экранировал "like this"\! или помещал полностью в одинарные кавычки 'like this!', а не в двойные кавычки.

# 1. hex; escape `!` by removing it from within the double quotes 
# and escaping it with `\!`
$ echo -e "She said, \x22Let\x27s get coding"\!"\x22"
She said, "Let's get coding!"

# OR put it all within single quotes:
$ echo -e 'She said, \x22Let\x27s get coding!\x22'
She said, "Let's get coding!"


# 2. octal; escape `!` by removing it from within the double quotes 
$ echo -e "She said, \042Let\047s get coding"\!"\042"
She said, "Let's get coding!"

# OR put it all within single quotes:
$ echo -e 'She said, \042Let\047s get coding!\042'
She said, "Let's get coding!"


# 3. mixed hex and octal, just for fun
# escape `!` by removing it from within the double quotes when it is followed by
# another escape sequence
$ echo -e "She said, \x22Let\047s get coding! It\x27s waaay past time to begin"\!"\042"
She said, "Let's get coding! It's waaay past time to begin!"

# OR put it all within single quotes:
$ echo -e 'She said, \x22Let\047s get coding! It\x27s waaay past time to begin!\042'
She said, "Let's get coding! It's waaay past time to begin!"

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

$ echo -e "She said, \x22Let\047s get coding! It\x27s waaay past time to begin!\042"
bash: !\042: event not found

OR:

$ echo -e "She said, \x22Let\x27s get coding!\x22"
bash: !\x22: event not found

Использованная литература:

  1. https://en.wikipedia.org/wiki/ASCII#Printable_characters
  2. https://serverfault.com/questions/208265/what-is-bash-event-not-found/208266#208266
  3. См. Также мой другой ответ здесь: Как мне писать символы, отличные от ASCII, с помощью echo?.
person Gabriel Staples    schedule 25.01.2021

Эта функция:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

позволяет цитировать ' внутри '. Используйте как это:

$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

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

#!/bin/bash

quote ()
{
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

while read line; do
    quote "$line"
done <<-\_lines_to_quote_
urxvt -fg '#111111' -bg '#111111'
Louis Theroux's LA Stories
'single quote phrase' "double quote phrase"
_lines_to_quote_

Выведет:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'

Все строки в правильных кавычках заключены в одинарные кавычки.

person Community    schedule 21.11.2015

Вот еще одно решение. Эта функция примет единственный аргумент и соответствующим образом процитирует его с помощью символа одиночной кавычки, как объясняется в ответе на голосование выше:

single_quote() {
  local quoted="'"
  local i=0
  while [ $i -lt ${#1} ]; do
    local ch="${1:i:1}"
    if [[ "$ch" != "'" ]]; then
      quoted="$quoted$ch"
    else
      local single_quotes="'"
      local j=1
      while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
        single_quotes="$single_quotes'"
        ((j++))
      done
      quoted="$quoted'\"$single_quotes\"'"
      ((i+=j-1))
    fi
    ((i++))
  done
  echo "$quoted'"
}

Итак, вы можете использовать это так:

single_quote "1 2 '3'"
'1 2 '"'"'3'"'"''

x="this text is quoted: 'hello'"
eval "echo $(single_quote "$x")"
this text is quoted: 'hello'
person exbuddha    schedule 27.11.2015