Расширение параметра (расширение переменной) и кавычки в кавычках

Работая в оболочке (Unix), иногда мне нужно заключать в двойные кавычки или наоборот, т.е. писать что-то вроде "foo 'bar baz' moo" или же 'foo "bar baz" moo', Это может быть потому, что

  • результирующая строка будет проанализирована снова (как с evalс ракушкой watchс ракушкой sshd на некотором удаленном сервере и т. д.) и эти внутренние кавычки имеют решающее значение для различения реальных аргументов во время этого второго анализа;
  • или мне просто нужен исходный аргумент для включения кавычек по любой другой причине.

Некоторая двусмысленность появляется, когда вместо bar baz У меня есть переменная, скажем $variable, Вот что говорит POSIX:

2.2.2. Одиночные кавычки

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

2.2.3 Двойные кавычки

Заключение символов в двойные кавычки ("") должен сохранять буквальное значение всех символов в двойных кавычках, за исключением символов обратной кавычки, <знак доллара>и <обратный слэш>, следующим образом:

$
Они сохранят свое особое значение, представляя расширение параметров […], форму подстановки команд […] и арифметическое расширение […].

[...]

Не совсем очевидно, какое правило применяется для $variable внутри одинарных кавычек внутри двойных кавычек (или внутри двойных кавычек внутри одинарных кавычек), поэтому я спрашиваю:

  1. Какое правило относится к:

    • variable=123
      echo "'$variable'"
      
    • variable=123
      echo '"$variable"'
      

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

  2. Есть ли исключения, причуды, сюрпризы?

    (Обратите внимание, что ниже приведен ответ вики-сообщества. Вместо того, чтобы добавлять отдельный ответ с другим исключением или причудой, рассмотрите возможность добавления вики-сообщества).

1 ответ

Решение

Какое правило применяется?

Просто пытаясь:

  • $ variable=123
    $ echo "'$variable'"
    '123'
    $
    
  • $ variable=123
    $ echo '"$variable"'
    "$variable"
    $
    

Так что внешние цитаты имеют значение. Обычные оболочки ведут себя так же: sh, bash, dash, zsh... Это из-за этого общего правила:

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

(источник)

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


Есть ли исключения, причуды, сюрпризы?

(Что ж, echo может преподнести несколько сюрпризов, см. Почему printf лучше чем echo ? Тем не менее, это отдельная проблема. Для удобства чтения ответ использует echo с безопасным значением $variable ).

  1. Приведенный выше код дает нам либо '123' или же "$variable", Что если нам нужно "123" или же '$variable'?

    • Получить "123":

      variable=123
      echo "\"$variable\""
      #     ^^         ^^   escaped inner quotes
      

      или же

      variable=123
      echo '"'"$variable"'"'
      #    1 12         23 3   outer quotes (numbered pairs)
      #     ^  ^^^^^^^^^  ^    quoted fragments
      
    • Получить '$variable':

      variable=123
      echo "'"'$variable'"'"
      #    1 12         23 3   outer quotes (numbered pairs)
      #     ^  ^^^^^^^^^  ^    quoted fragments
      
  2. Вопрос отмечает, что $ сохраняет свое особое значение в двойных кавычках. Это важно:

    Входные символы в строке в кавычках, которые также заключены между $( и соответствие ) не должны затрагиваться двойными кавычками, а скорее должны определять ту команду, чей вывод заменяет $(…) когда слово развернуто.

    (источник)

    Это означает цитирование внутри $(…) следует рассматривать независимо, несмотря на внешние двойные кавычки. В самом деле:

    $ variable=123
    $ echo "$(echo 'foo $variable')"
    $ #            ^             ^   single-quotes matter!
    foo $variable
    $
    

    (Заметка echo $(stuff) плохой код в целом; это здесь, чтобы проиллюстрировать текущую проблему).

    В этих двух случаях:

    • echo "'$variable'" (попробовал выше)
    • echo "$(echo 'foo $variable')" (обсуждается здесь)

    есть $variable внутри одинарных кавычек внутри двойных кавычек, но $(…) сильно меняется Аналогичная ситуация с echo "`echo 'foo $variable'`" (хотя $(…) и галочки не совсем эквивалентны).

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