Co to jest ~ (tylda), gdy jest używany jako prefiks ścieżki?

11

Edycja: Jest to duplikat /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . Nie mam reputacji, aby zamknąć to pytanie jako duplikat.

Nie mówię o tym ~jak w katalogu domowym, ale raczej o tym:

$ ls ~foo/bar
/some/mount/point/foo/bar

Jeśli jednak spróbuję użyć innego punktu montowania, np .:

$ mount | ag "/dev "
devfs on /dev (devfs, local, nobrowse)
$ ls /dev/stdin
/dev/stdin
$ ls ~stdin
zsh: no such user or named directory: stdin . 
# bash has a similar error message: 
ls: ~stdin: No such file or directory

Jak ~nazywa się w tym kontekście? Jak to działa?

Edycja: Więcej informacji na podstawie niektórych poniższych komentarzy:

  1. Mogę zaświadczyć, że foonie jest to nazwa użytkownika w moim systemie.
  2. Podczas próby autouzupełniania ls -lah ~nie są wyświetlane wszystkie opcje. tzn. jestem w stanie cd ~qux, gdy quxnie pojawia się w autouzupełnianiu. Ponownie quxnie jest użytkownikiem w moim systemie.
  3. Jeśli to ważne, /some/mount/pointto udział sieciowy.
  4. Wszystkie szczegóły sugerują pewne nazwane muckery ścieżek, funkcję powłoki Z w rozszerzaniu nazw ścieżek, ale działa to również w bash, która najwyraźniej nie obsługuje rzeczy takich jak nazwane ścieżki powłoki Z.
R & D
źródło
5
~foojest katalogiem domowym użytkownika foo. Jeśli użytkownik nie zostanie określony, bieżącym użytkownikiem będzie domyślny.
DopeGhoti
Ale w tym przypadku /some/mount/pointzdecydowanie nie jest to mój katalog domowy. cd ~zabiera mnie do - /Users/$username/które mecze$HOME
RD
1
zshwydaje się również używać tyldy do wskazania nazwanych katalogów.
DopeGhoti
Podejrzewałem to też !! Z jakiegoś powodu seria poleceń, które opublikowałem powyżej, działa również w bash ( bash -c "ls ~foo/bar") - która nie ma nazwanych katalogów. Co więcej, nawet w Zsh, jeśli sprawdzę env, nie widzę skonfigurowanych nazwanych katalogów. Korzystam z systemu Mac OS i wydaje mi się, że jest to funkcja specyficzna dla systemu OS X.
RD
1
Ty tylko powiedziałeś ~foo. Weź aktualny ciąg (nie przykład foo) i zrób grep "actual username" /etc/passwd. ~textpowinien działać tylko dla możliwych nazw logowania, zgodnie z instrukcją bash (niekoniecznie oznacza, że ​​jest w stanie się zalogować; w przypadku użytkowników systemu, takich jak ~lpna przykład). We wszystkich moich testach ~stringodpowiada to stringbyciu nazwą użytkownika.
Sergiy Kolodyazhnyy

Odpowiedzi:

14

Co to jest ~ foo

Cytat z podręcznika bash (z dodatkowym naciskiem):

Jeśli słowo zaczyna się od niecytowanego znaku tyldy (`~ '), wszystkie znaki poprzedzające pierwszy niecytowany ukośnik (lub wszystkie znaki, jeśli nie ma cudzysłowu) są uważane za prefiks tyldy. Jeśli żaden z znaków w cytowany jest przedrostek tyldy, znaki w przedrostku tyldy po znaku tyldy są traktowane jako możliwa nazwa logowania.

~foo rozwija się do fookatalogu domowego użytkownika dokładnie tak, jak określono w /etc/passwd. Uwaga: może to obejmować nazwy użytkowników systemu; niekoniecznie oznacza to użytkowników lub fakt, że mogą oni logować się lokalnie (mogą na przykład logować się za pomocą kluczy SSH).

W rzeczywistości, jak zauważono w komentarzach , bashużyje getpwnamfunkcji. Że sama funkcja jest określona przez POSIX standardzie, dlatego powinna istnieć na większości systemów uniksowych, w tym MacOS X . Ta funkcja nie ogranicza się /etc/passwdtylko do wyszukiwania innych baz danych, takich jak LDAP i NIS. Szczególny fragment bash kodu źródłowego , tilde.cpliku, zaczynający się od linii 394:

  /* No preexpansion hook, or the preexpansion hook failed.  Look in the
     password database. */
  dirname = (char *)NULL;
#if defined (HAVE_GETPWNAM)
  user_entry = getpwnam (username);
#else
  user_entry = 0;

Praktyczny przykład

Poniżej możesz zobaczyć testy z nazwami użytkowników systemu w moim systemie. Zwróć uwagę na odpowiedni passwdwpis i wynikls ~username

$ grep '_apt' /etc/passwd
_apt:x:104:65534::/nonexistent:/bin/false
$ ls ~_apt
ls: cannot access '/nonexistent': No such file or directory
$ grep '^lp' /etc/passwd
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
$ ls ~lp
ls: cannot access '/var/spool/lpd': No such file or directory

Nawet jeśli na przykład _aptkonto jest zablokowane, jak sugeruje dane wyjściowe passwd -S apt, nadal wyświetla się jako możliwa nazwa logowania:

_apt L 11/29/2017 0 99999 7 -1

Uwaga: To nie jest funkcja specyficzna dla systemu macOS, ale funkcja specyficzna dla powłoki.

Sergiy Kolodyazhnyy
źródło
Wątpię, aby powłoka mogła polegać na dowiedzeniu się czegoś o dacie wygaśnięcia konta lub o tym, czy jest zablokowana, czy cokolwiek podczas rozwijania tyldy. Np. W systemie Linux data ważności jest przechowywana /etc/shadowwraz z innymi chronionymi informacjami uwierzytelniającymi, takimi jak hasło. Odwołanie passwddotyczy tylko unieważnienia hasła: nie zapobiegnie to uwierzytelnieniu w inny sposób.
ilkkachu
@ilkkachu Tak, masz rację. Testowałem to z dodawaniem testuseri modyfikowaniem daty ważności hasła. Nazwa użytkownika nadal pojawia się po zakończeniu zakładki.
Usunąłem
1
Jedynym problemem związanym z tą odpowiedzią jest to, że cytuje bashstronę podręcznika (i wydaje się, że jest to stara). OP faktycznie używa zsh(mogłoby być jaśniej), chociaż w komentarzach wspomniano, że bashma takie samo zachowanie.
Ken Wayne VanderLinde
2
Możesz użyć getent passwd foozamiast grep foo /etc/passwordtych samych mechanizmów wyszukiwania co powłoka - być może włączając w to sieciowe usługi katalogowe wspomniane przez @Abigail.
RJHunter
1
Zaakceptowano jako odpowiedź na bit „taki jak LDAP i NIS”, który w moim przypadku był poprawny!
RD
5

Podsumowując, dlaczego coś widzisz ~foo/bar, to dlatego, że masz w systemie użytkownika o nazwie fooz folderem o nazwie barw jego katalogu domowym.

Zobacz to rozwiązanie w innej społeczności, która wyjaśnia, dlaczego (tylda) ~to coś więcej niż „katalog domowy”.

Jeśli masz w systemie użytkownika o nazwie bin, możesz wyświetlić zawartość katalogu domowego bin za pomocą polecenia:

ls ~bin

Inną rzeczą, którą możesz wypróbować, jest użycie uzupełniania tabulacji po wpisaniu następującego polecenia (nie wracaj do powrotu, wystarczy użyć klawisza tab):

ls -lah ~ tab

aby zobaczyć listę katalogów domowych użytkowników, ~które rozwiną się, jeśli będziesz kontynuować. Przykład (obcięty) wynik tabulacji zls -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/
WEBjuju
źródło
1
+1 za uzupełnienie karty. To wyraźnie pokazuje wszystkie nazwy użytkowników, z których bash może uzyskać jak najwięcej nazw logowania /etc/passwd. Natychmiast pomaga wyjaśnić, co się dzieje, jeśli użytkownik oczywiście zna nazwy użytkowników, które mają w systemie.
Sergiy Kolodyazhnyy
2
Dzięki za wskazówkę na temat zakończenia bashu - przyniosło kilka interesujących wyników autouzupełniania. Chociaż ~foowykonałem autouzupełnianie, mogę zaświadczyć, że foonie jest użytkownikiem w moim systemie (i faktycznie nie istnieje /etc/passwd). Ponadto wszystkie foldery / pliki /some/mount/pointpojawiają się w autouzupełnianiu, co jest bardzo interesujące.
RD