Почему тильда (~) не раскрывается в двойных кавычках?

54

Согласно этому ответу и моему собственному пониманию, тильда расширяется до домашнего каталога:

$ echo ~
/home/braiam

Теперь, когда я хочу, чтобы раскрытие оболочки работало, то есть с использованием таких имен переменных $FOO, а не прерывалось из-за непредвиденных символов, таких пробелов и т. Д., Следует использовать двойные кавычки ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

Почему это расширение не работает с тильдой?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
источник
3
Также обратите внимание, что это имеет несоответствие при предоставлении аргумента программы в командной строке, который в аргументе команды --path ~/myfileрасширяется, но --path=~/myfileне расширяется .
Анхель
Связанный: всегда ли ~ равен $ HOME
Стефан Шазелас
Вариант на эту тему - unix.stackexchange.com/questions/279565 .
JdeBP

Ответы:

45

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

POSIX определяет двойные кавычки как:

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

...

Приложение должно гарантировать, что двойной кавычке предшествует обратная косая черта для включения в двойные кавычки. Параметр «@» имеет особое значение в двойных кавычках

За исключением случаев $, `, \и @, другие символы рассматриваются как литералы в двойных кавычках.

cuonglm
источник
9
В этом случае я думаю, вы должны использовать $HOME.
Сет
11
Или вы можете просто не цитировать ~, напримерls -l ~/"My Documents"
Эндрю Медико
Это очень не интуитивно понятно. По какой причине они решили сделать это? (Этот ответ на самом деле не дает причину, а скорее указывает на стандарт, но, по-видимому, стандарт был написан именно так по причине .)
иконоборчество
1
@iconoclast, если вы действительно хотите «почему они были реализованы таким образом», прочитайте вместо этого ответ Стефана .
Брайам
2
Так, @iconoclast, почему это небо голубое? :) :) :)
Джесси Чизхольм
32

Расширение тильды определяется POSIX как:

А «тильда-префикс» не состоит из некотируемого <тильды> символа в начале слова, после чего всех символов , предшествующих первого без кавычек <слэша> в слове, или все символы в слове , если нет < слэш>. В назначении можно использовать несколько префиксов тильды: [...] после <знака равенства> назначения, после любого <двоеточия> без кавычек или обоих. [...] Если ни один из символов в префиксе тильды не заключен в кавычки, символы в префиксе тильды, следующие за <тильдой>, рассматриваются как возможное имя для входа в систему из пользовательской базы данных. [...] Если имя для входа в систему равно нулю (т. Е. Префикс тильды содержит только тильду), префикс тильды заменяется значением переменной HOME. Если HOME не установлен, результаты не уточняются. [...]

Таким образом, самый короткий ответ «потому что он определен таким образом»: цитирование любого из символов в префиксе, в том числе ~, запрещает расширение.

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

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

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

$ cat ~/"file name with spaces"

В более широком смысле «почему»: поскольку для разделения слов не существует мыслимого использования ~, это должно быть поведение по умолчанию, а не требование его заключать в кавычки. Поскольку нет необходимости ~заключать его в кавычки, придание особого значения внутри кавычек было бы ненужным осложнением. И, конечно же, исторические причины означают, что его нельзя изменить сейчас, даже если это было бы желательно.

Майкл Гомер
источник
Согласно этому Баш руководство , тильды происходит перед тем разделением пробелами. Есть ли способ безопасно выполнить расширение тильды, даже если в вашем домашнем каталоге есть пробелы? Обычно, конечно, вы бы делали такие вещи с "".
Лукретиэль
Расширение - это одно слово; см. второй процитированный отрывок в ответе.
Майкл Гомер
23

~ происходит в C-оболочке задолго до того, как она была добавлена ​​в оболочку Korn, а затем добавлена ​​в спецификацию оболочки POSIX.

В C-оболочке ~был оператор сглаживания (расширенный той же самой процедурой, что и расширяющий, *.txtнапример), поэтому, как и остальная часть смещения, не выполнялась в двойных кавычках.

Стефан Шазелас
источник
11

Хотя это не отвечает на вопрос, почему он разработан таким образом, $HOMEвместо этого вы используете, если вам нужно заменить, поскольку это, по сути, то, что ~делает.

$ echo "$HOME/some/path"
/home/braiam/some/path
Объединяется
источник
6
это не работает с~otheruser
Йоханнес Кун
2
Правда, но вы могли бы сделать: THEM = ~ otheruser, затем использовать «$ THEM / some / path»
melds
1
Обходной путь ~otheruserпоказывает, какая плохая идея - обращаться с ~переменными и другими вещами, которые раскрываются в двойных кавычках.
иконоборчество