Czy ~ zawsze równa się $ HOME

40

Wiem, że prawdopodobnie o to wcześniej pytano, ale nie mogłem tego znaleźć w Google.

Dany

  • Jądro Linux
  • Brak konfiguracji zmieniających $ HOME
  • grzmotnąć

Będzie ~ == $HOMEprawda

PythonNut
źródło
3
Myślę, że tak, ale nie jest to problem związany z Linuksem. Wierzę raczej, że ~będzie to odpowiednik $HOMEw dowolnym środowisku POSIX; ale mogę się mylić.
HalosGhost
4
Pomimo poniższych odpowiedzi… nie zawsze. Porównaj echo "~"i echo "$HOME".
Sparhawk
@Sparhawk Czekaj, więc 1 + 1 nie jest 2? To spisek! Rząd coś przed nami ukrywa! : P
Klamka
1
@Sparhawk, zauważysz, że OP faktycznie nie zacytował ani, ~ani $HOME. : P
HalosGhost
2
@HalosGhost Ah, dobra uwaga. (Także, ja później zauważył, że Michael Homera odpowiedź wspomina „pojedynczy cytowane ~”). W każdym razie, coś, aby pamiętać, dla zwykłego czytelnika, podobnie jak ja.
Sparhawk

Odpowiedzi:

46

Ważne jest, aby zrozumieć, że ~rozszerzenie jest cechą powłoki (niektórych powłok), nie jest magiczną postacią, niż oznacza katalog domowy, gdziekolwiek jest używany.

Jest rozszerzany (przez powłokę, która jest aplikacją służącą do interpretacji wiersza poleceń), podobnie jak $varjest rozszerzany do jego wartości w pewnych warunkach, gdy jest używany w linii poleceń powłoki przed wykonaniem polecenia.

Ta funkcja pojawiła się po raz pierwszy w powłoce C pod koniec lat siedemdziesiątych (powłoka Bourne'a nie miała jej, podobnie jak jej poprzedniczka - powłoka Thompson), została później dodana do powłoki Korn (nowsza powłoka zbudowana na powłoce Bourne'a w 80s). Ostatecznie został ustandaryzowany przez POSIX i jest teraz dostępny w większości powłok, w tym takich jak non-POSIX fish.

Ponieważ jest tak szeroko stosowany w powłokach, niektóre aplikacje inne niż powłoki również rozpoznają go jako oznaczający katalog domowy. Tak jest w przypadku wielu zastosowań w swoich plikach konfiguracyjnych lub ich własnej linii poleceń ( mutt, slrn, vim...).

bashkonkretnie (która jest powłoką projektu GNU i szeroko stosowana w wielu systemach operacyjnych opartych na Linuksie), gdy jest wywoływana jako sh, przeważnie przestrzega reguł POSIX dotyczących ~ekspansji, aw obszarach nieokreślonych przez POSIX zachowuje się głównie jak powłoka Korna (z który jest częściowym klonem).

Chociaż $varjest rozwijany w większości miejsc (z wyjątkiem pojedynczych cudzysłowów), ~ekspansja, będąca refleksją, jest rozwijana tylko w kilku konkretnych warunkach.

Jest rozwijany, gdy sam argument w kontekstach list, w kontekstach, w których oczekiwany jest ciąg znaków.

Oto kilka przykładów jego rozszerzenia bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(wymagane przez POSIX, używanego dla zmiennych podoba PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](rozszerzenie ~jest traktowane jako wzór w AT&T, kshale nie bashod 4.0).
  • case ~ in ~) ...
  • ${var#~} (choć nie w innych powłokach)
  • cmd foo=~(choć nie przy wywołaniu jako shi tylko wtedy, gdy to, co znajduje się po lewej stronie =ma kształt niecytowanej bashnazwy zmiennej)
  • cmd ~/x (oczywiście wymagane przez POSIX)
  • cmd ~:x(ale nie x:~:xlub x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (nie w niektórych innych powłokach)

Oto kilka przykładów, w których nie jest rozwinięty:

  • echo "~" '~'
  • echo ~@ ~~(zauważ również, że ~uma on na celu rozszerzenie do katalogu domowego użytkownika u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • z extglob: case $var in @(~|other))...(choć case $var in ~|other)jest OK).
  • ./configure --prefix=~(ponieważ --prefixnie jest prawidłową nazwą zmiennej)
  • cmd "foo"=~(w bash, ze względu na cytaty).
  • gdy wywołany jako sh: export "foo"=~, env JAVA_HOME=~ cmd...

Jeśli chodzi o to, do czego się rozwija: ~sam rozwija się do zawartości HOMEzmiennej lub, gdy nie jest ustawiona, do katalogu domowego bieżącego użytkownika w bazie danych kont (jako rozszerzenie, ponieważ POSIX pozostawia to zachowanie niezdefiniowane).

Należy zauważyć, że w ksh88 i bashwersjach wcześniejszych niż 4.0 ekspansja tyldy przeszła globbing (generowanie nazw plików) w kontekście list:

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

Nie powinno to stanowić problemu w zwykłych przypadkach.

Pamiętaj, że ponieważ jest rozwinięty, to samo ostrzeżenie ma zastosowanie do innych form rozszerzeń.

cd ~

Nie działa, jeśli $HOMEzaczyna się od -lub zawiera ..składniki. Tak więc, chociaż jest bardzo mało prawdopodobne, aby kiedykolwiek coś zmienić, ściśle mówiąc, należy napisać:

cd -P -- ~

Lub nawet:

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

(w celu pokrycia wartości $HOMEpodobnych -, +2...) lub po prostu:

cd

(jak cdzabierze Cię do katalogu domowego bez żadnych argumentów)

Inne pociski mają bardziej zaawansowane ~rozszerzenia. Na przykład w zsh:

  • ~4, ~-, ~-2(W realizacji) wykorzystywane do rozszerzenia katalogi w stosie Directory (miejsc, które już cdsię wcześniej).
  • dynamiczne katalogi nazwane . Możesz zdefiniować własny mechanizm decydujący o sposobie ~somethingrozbudowy.
Stéphane Chazelas
źródło
25

W dowolnej wersji Bash na dowolnym systemie, tak . ~jako termin definiowany jest jako rozszerzenie do:

Wartość $ HOME

więc zawsze będzie taki sam, jak $HOMEdla bieżącej powłoki. Istnieje kilka innych rozszerzeń tyldy, na przykład ~userdla userkatalogu domowego, ale pojedynczy sam w cudzysłowie ~zawsze będzie się rozwijał "$HOME".

Należy zauważyć, że zachowanie od ~i $HOMEmoże być różny w niektórych przypadkach: w szczególności, jeśli $HOMEzawiera spacje (lub inne IFS znaków), a następnie $HOME(cytowane) wzrośnie do kilku słów, a ~to zawsze jedno słowo. ~rozwija się równorzędnie do "$HOME"(cytowany).

W odniesieniu do twojego konkretnego pytania:

[[ $HOME == ~ ]]

jest zawsze prawdziwe, ponieważ [[ eliminuje dzielenie słów. [[ ~ == $HOME ]może nie być, jeśli HOMEzawiera znaki pasujące do wzorca , ale [[ ~ == "$HOME" ]](tj. cytowane "$HOME") jest zawsze prawdziwe. Używanie go w nawiasach pojedynczych może być błędem składniowym dla wartości HOMEzawierających spacje lub znaki specjalne. Dla każdej sensownej konfiguracji katalogu domowego ~i "$HOME"są takie same i porównać jako równe.


Stéphane Chazelas zauważył przypadek w komentarzach gdzie ~i $HOMEpodaje różne wartości: jeśli ty unset HOME, to kiedy użyjesz ~Bash zadzwoni, getpwuidaby odczytać wartość z bazy danych haseł. Ten przypadek jest wykluczony z powodu braku zmiany konfiguracji $HOME, ale wspomnę o tym tutaj dla kompletności.

Michael Homer
źródło
1
Jednak /bin/shmoże nie być bash. Nie jestem pewien, czy shspecyfikacja Posix mówi~
Basile Starynkevitch
1
POSIX określa ~. ~nie było w skorupie Thomsona ani Bourne'a (które w swoim czasie były dostępne jako /bin/sh). Nie ma go ani nie rcjest pochodną (gdzie jest używany do czegoś innego)
Stéphane Chazelas
5
W kilku powłokach, w tym bash, jeśli nie HOMEjest ustawiony, ~rozwija się do katalogu domowego użytkownika z bazy danych passwd. Jest to przypadek, w którym ~może nie rozwinąć się do wartości $HOME.
Stéphane Chazelas
1
Zauważ, że bashprzed bash4 używał globowania po rozwinięciu tyldy (try HOME='/*' bash -c 'echo /*'). Zwróciłby więc HOME=/*; [ "$HOME" = ~ ]tam błąd.
Stéphane Chazelas
4
@cuonglm Sprawdziłem kod źródłowy. To ostatecznie wzywa get_current_user_info , który wykorzystuje getpwuidna wszystkich platformach, ale Tandem .
Michael Homer