Всегда ли ~ равен $ HOME

40

Я знаю, что, возможно, об этом уже спрашивали, но я не смог найти его в Google.

Данный

  • Ядро Linux
  • Нет конфигураций, которые изменяют $ HOME
  • удар

Будет ~ == $HOMEправдой?

PythonNut
источник
3
Я верю в это, но это не проблема Linux. Скорее, я верю, что ~это будет эквивалентно $HOMEлюбой среде POSIX; но я могу ошибаться
HalosGhost
4
Несмотря на ответы ниже ... не всегда. Сравните echo "~"и echo "$HOME".
Sparhawk
@ Sparhawk Подождите, так что 1 + 1 не 2? Это заговор! Правительство что-то скрывает от нас! : P
Дверная ручка
1
@ Sparhawk, вы заметите, что ОП на самом деле не цитирует ни, ~ни $HOME. : P
HalosGhost
2
@HalosGhost Ах, хорошая мысль. (Кроме того, я позже заметил, что в ответе Майкла Гомера упоминается «без кавычек ~».) В любом случае, что-то, что нужно иметь в виду для случайного читателя, такого как я.
Sparhawk

Ответы:

46

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

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

Эта функция впервые появилась в C-оболочке в конце 1970-х годов (у оболочки Bourne ее не было, равно как и у ее предшественницы - оболочки Томпсона), а затем была добавлена ​​в оболочку Korn (более новую оболочку, построенную на оболочке Bourne в 80 - е годы). В конечном итоге он был стандартизирован POSIX и теперь доступен в большинстве оболочек, включая не POSIX, например fish.

Поскольку он широко используется в оболочках, некоторые приложения, не относящиеся к оболочке, также распознают его как домашний каталог. Вот случай из многих приложений , в их файлах конфигурации или их собственной командной строки ( mutt, slrn, vim...).

bashв частности (которая является оболочкой проекта GNU и широко используется во многих операционных системах на основе Linux), когда вызывается как sh, в основном следует правилам POSIX о ~расширении, а в областях, не указанных в POSIX, ведет себя в основном как оболочка Korn (из который является частью клона).

Хотя $varон раскрывается в большинстве мест (кроме внутри одинарных кавычек), ~расширение, будучи запоздалой мыслью, расширяется только в нескольких конкретных условиях.

Он раскрывается по своему собственному аргументу в контекстах списка, в контекстах, где ожидается строка.

Вот несколько примеров того, как он расширяется bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(требуется POSIX, используемый для таких переменных , как PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](расширение ~принимается как образец в AT & T, kshно не bashначиная с 4.0).
  • case ~ in ~) ...
  • ${var#~} (хотя не в некоторых других оболочках)
  • cmd foo=~(хотя не тогда, когда вызывается как sh, а только тогда, когда то, что слева, =имеет форму bashимени переменной без кавычек )
  • cmd ~/x (требуется POSIX, очевидно)
  • cmd ~:x(но не x:~:xили x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (не в некоторых других оболочках)

Вот несколько примеров, где это не раскрыто:

  • echo "~" '~'
  • echo ~@ ~~(также обратите внимание, что ~uпредполагается расширить до домашнего каталога пользователя u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • с extglob: case $var in @(~|other))...(хотя case $var in ~|other)все в порядке).
  • ./configure --prefix=~(поскольку --prefixне является допустимым именем переменной)
  • cmd "foo"=~( bashиз-за кавычек).
  • При вызове как sh: export "foo"=~, env JAVA_HOME=~ cmd...

Что касается того, что он расширяет: ~один расширяет содержимое HOMEпеременной или, если он не установлен, домашний каталог текущего пользователя в базе данных учетных записей (как расширение, поскольку POSIX оставляет такое поведение неопределенным).

Следует отметить, что в ksh88 и bashверсиях, предшествующих 4.0, расширение тильды подверглось глобализации (генерации имени файла) в контексте списка:

$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~

Это не должно быть проблемой в обычных случаях.

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

cd ~

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

cd -P -- ~

Или даже:

case ~ in
  (/*) cd -P ~;;
  (*) d=~; cd -P "./$d";;
esac

(для покрытия значений $HOMEвроде -, +2...) или просто:

cd

(так как cdвы попадете в ваш домашний каталог без всяких аргументов)

Другие оболочки имеют более продвинутые ~расширения. Например, у zshнас есть:

  • ~4, ~-, ~-2(С завершением) используется для расширения каталогов в вашем стеке каталогов (места можно cdраньше).
  • динамические именованные каталоги . Вы можете определить свой собственный механизм, чтобы решить, как ~somethingбудет расширяться.
Стефан Шазелас
источник
25

В любой версии Bash в любой системе, да . ~как термин сам по себе определяется для расширения до:

Значение $ HOME

поэтому он всегда будет таким же, как $HOMEи для текущей оболочки. Существует несколько других расширений тильды, например, ~userдля userдомашнего каталога, но одно отдельное без кавычек ~всегда будет расширяться до "$HOME".

Обратите внимание, что поведение в ~и $HOMEможет отличаться в некоторых случаях: в частности, если $HOMEсодержит пробелы (или другие IFS символы), то $HOME(без кавычек) будет расширяться до нескольких слов, в то время как ~это всегда одно слово. ~расширяется эквивалентно "$HOME"(цитируется).

Что касается вашего конкретного вопроса:

[[ $HOME == ~ ]]

всегда верно, потому что [[ подавляет разделение слов. [[ ~ == $HOME ]может не быть, еслиHOME есть символы соответствия шаблону , но [[ ~ == "$HOME" ]](то есть в кавычках "$HOME") всегда верно. Использование его в одинарных скобках может быть синтаксической ошибкой для значений, HOMEсодержащих пробелы или специальные символы. Для любой разумной конфигурации домашний каталог ~и "$HOME"то же самое и сравнивают как равные.


Стефан Chazelas отметил случай в комментариях, где ~и $HOMEдают разные значения: если вы unset HOME, то когда вы используете~ Bash вызовет getpwuidдля считывания значения из базы паролей. Этот случай исключен вашим состоянием отсутствия изменений конфигурации $HOME, но я упомяну его здесь для полноты.

Майкл Гомер
источник
1
Тем /bin/shне менее, не может быть bash. Я не уверен , что Posix shспецификация говорит о~
Basile Starynkevitch
1
POSIX указывает ~. ~не было в оболочке Томсона или Борна (которые в свое время были доступны как /bin/sh). Это не в rcили его производных (где это используется для чего-то еще)
Стефан Шазелас
5
В нескольких оболочках, в том числе bash, если HOMEне установлено, ~расширяется до домашнего каталога пользователя из базы данных passwd. Так что это тот случай, когда ~не может расширяться до значения $HOME.
Стефан Шазелас
1
Обратите внимание, что bashраньше bash4 использовался для подстановки при расширении тильды (попробуйте HOME='/*' bash -c 'echo /*'). Так HOME=/*; [ "$HOME" = ~ ]бы вернул ошибку там.
Стефан Шазелас
4
@cuonglm Я проверил исходный код. Это в конечном итоге звонки get_current_user_info , которые используются getpwuidна всех платформах, кроме Tandem .
Майкл Гомер