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


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


3
Также обратите внимание, что это имеет несоответствие при предоставлении аргумента программы в командной строке, который в аргументе команды --path ~/myfileрасширяется, но --path=~/myfileне расширяется .
Анхель



Вариант на эту тему - unix.stackexchange.com/questions/279565 .
JdeBP

Ответы:


45

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

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

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

...

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

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


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показывает, какая плохая идея - обращаться с ~переменными и другими вещами, которые раскрываются в двойных кавычках.
иконоборчество
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.