Was ist eine ~ (Tilde), wenn sie als Präfix für einen Pfad verwendet wird?

11

Bearbeiten: Dies ist ein Duplikat von /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . Ich habe nicht den Ruf, diese Frage als Duplikat zu schließen.

Ich beziehe mich nicht auf ~das Home-Verzeichnis, sondern auf Folgendes:

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

Wenn ich es jedoch mit einem anderen Einhängepunkt versuche, z.

$ 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

Wie heißt das ~in diesem Zusammenhang? Wie funktioniert es?

Bearbeiten: Weitere Informationen basierend auf einigen der folgenden Kommentare:

  1. Ich kann bestätigen, dass dies fookein Benutzername auf meinem System ist.
  2. Beim Versuch der automatischen Vervollständigung werden ls -lah ~nicht alle Optionen angezeigt. dh ich kann cd ~qux, wenn quxnicht in der Autovervollständigung angezeigt wird. Wieder quxist kein Benutzer in meinem System.
  3. Wenn es darauf ankommt, /some/mount/pointhandelt es sich um eine Netzwerkfreigabe.
  4. Alle Details deuten auf ein benanntes Pfad-Muckery hin, eine Z-Shell-Funktion der Pfadnamenerweiterung, aber dies funktioniert auch in Bash, das anscheinend Dinge wie die benannten Pfade der Z-Shell nicht unterstützt.
RD
quelle
5
~fooist das Home-Verzeichnis des Benutzers foo. Wenn der Benutzer nicht angegeben ist, ist der aktuelle Benutzer der Standard.
DopeGhoti
Aber in diesem Fall ist /some/mount/pointdefinitiv nicht mein Home-Verzeichnis. cd ~bringt mich zu - /Users/$username/welche Spiele$HOME
RD
1
zshscheint auch die Tilde zu verwenden, um benannte Verzeichnisse anzugeben.
DopeGhoti
Das habe ich auch vermutet !! Aus irgendeinem Grund funktioniert die oben veröffentlichte Befehlsreihe auch in bash ( bash -c "ls ~foo/bar") - ohne benannte Verzeichnisse. Außerdem envsehe ich selbst innerhalb von zsh, wenn ich das inspiziere , keine benannten Verzeichnisse eingerichtet. Ich bin unter Mac OS und ich denke, dies ist eine spezifische Funktion für OS X.
RD
1
Du hast nur gesagt ~foo. Nehmen Sie die eigentliche Zeichenfolge (nicht das Beispiel foo) und tun Sie dies grep "actual username" /etc/passwd. ~textsollte nur für mögliche Login-Benutzernamen gemäß dem Bash-Handbuch funktionieren (bedeutet nicht unbedingt, dass es tatsächlich möglich ist, sich anzumelden; bei Systembenutzern wie ~lpzum Beispiel). In all meinen Tests ~stringentspricht das stringdem Benutzernamen.
Sergiy Kolodyazhnyy

Antworten:

14

Was ist ~ foo

Zitat aus dem Bash-Handbuch (mit zusätzlicher Betonung):

Wenn ein Wort mit einem nicht zitierten Tilde-Zeichen (`~ ') beginnt, werden alle Zeichen vor dem ersten nicht zitierten Schrägstrich (oder alle Zeichen, wenn kein nicht zitierter Schrägstrich vorhanden ist) als Tilde-Präfix betrachtet Tilde-Präfix wird in Anführungszeichen gesetzt, die Zeichen im Tilde-Präfix nach der Tilde werden als möglicher Anmeldename behandelt .

~foo Erweitert das fooAusgangsverzeichnis des Benutzers genau wie in angegeben /etc/passwd. Beachten Sie, dass dies Systembenutzernamen umfassen kann. Dies bedeutet nicht unbedingt, dass menschliche Benutzer sich tatsächlich lokal anmelden können (sie können sich beispielsweise über SSH-Schlüssel anmelden).

Tatsächlich wird, wie in den Kommentaren angegeben , bashdie getpwnamFunktion verwendet. Diese Funktion selbst ist im POSIX- Standard festgelegt und sollte daher auf den meisten Unix-ähnlichen Systemen, einschließlich macOS X, vorhanden sein . Diese Funktion ist nicht nur auf /etc/passwdandere Datenbanken wie LDAP und NIS beschränkt und durchsucht diese. Besonderer Auszug aus bash Quellcode , tilde.cDatei, ab Zeile 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;

Praktisches Beispiel

Unten sehen Sie Tests mit Systembenutzernamen auf meinem System. Achten Sie auf den entsprechenden passwdEintrag und das Ergebnis vonls ~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

Auch wenn zum Beispiel das _aptKonto gesperrt ist, wie durch die Ausgabe vorgeschlagen, wird passwd -S aptes immer noch als möglicher Anmeldename angezeigt:

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

Bitte beachten Sie: Dies ist keine macOS-spezifische Funktion, sondern eine Shell-spezifische Funktion.

Sergiy Kolodyazhnyy
quelle
Ich bezweifle, dass sich die Shell darauf verlassen kann, dass sie etwas über das Ablaufdatum des Kontos herausfindet oder ob es gesperrt ist oder irgendetwas, wenn die Tilde erweitert wird. Unter Linux wird beispielsweise das Ablaufdatum /etc/shadowzusammen mit den anderen geschützten Authentifizierungsinformationen wie dem Kennwort gespeichert . Bei der Referenz in passwdgeht es nur darum, das Kennwort ungültig zu machen: Dies würde die Authentifizierung auf andere Weise nicht verhindern.
Ilkkachu
@ilkkachu Ja, du hast recht. Ich habe das mit dem Hinzufügen testuserund Ändern des Kennwortablaufdatums getestet . Der Benutzername wird weiterhin in Tab-Vervollständigung angezeigt. Ich habe dieses Bit aus der Antwort entfernt
Sergiy Kolodyazhnyy
1
Das einzige Problem mit dieser Antwort ist, dass sie die bashManpage zitiert (und anscheinend die alte). Das OP verwendet tatsächlich zsh(hätte klarer sein können), obwohl in den Kommentaren erwähnt wird, dass bashes das gleiche Verhalten hat.
Ken Wayne VanderLinde
2
Sie können getent passwd foostattdessen grep foo /etc/passworddieselben Suchmechanismen wie die Shell verwenden, um möglicherweise netzwerkbasierte Verzeichnisdienste einzuschließen, die von @Abigail erwähnt werden.
RJHunter
1
Akzeptiert als Antwort auf das Bit "wie LDAP und NIS", das in meinem Fall richtig war!
RD
5

Zusammenfassend lässt sich sagen, warum Sie etwas sehen ~foo/bar, weil Sie einen Benutzer fooauf dem System mit einem Ordner barin seinem Ausgangsverzeichnis haben.

Sehen Sie sich diese Lösung in einer anderen Community an , in der erklärt wird, warum (Tilde) ~mehr als nur ein "Home-Verzeichnis" ist.

Wenn binauf Ihrem System ein Benutzer benannt ist, können Sie den Inhalt des Home-Verzeichnisses von bin mit dem folgenden Befehl auflisten:

ls ~bin

Sie können auch versuchen, die Tab-Vervollständigung zu verwenden, nachdem Sie an einer Eingabeaufforderung Folgendes eingegeben haben (kein Wagenrücklauf, verwenden Sie einfach die Tabulatortaste):

ls -lah ~ tab

um die Liste der Home-Verzeichnisse der Benutzer anzuzeigen, ~die erweitert werden, wenn Sie fortfahren. Beispielausgabe (abgeschnitten) der Tab-Vervollständigung vonls -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/
WEBjuju
quelle
1
+1 für die Tab-Vervollständigung. Dies zeigt deutlich alle Benutzernamen, von denen bash möglichst Anmeldenamen erhalten kann /etc/passwd. Es hilft sofort zu klären, was los ist, wenn der Benutzer natürlich die Benutzernamen kennt, die er auf dem System hat.
Sergiy Kolodyazhnyy
2
Vielen Dank für den Tipp zum Abschluss der Bash - dies führte zu einigen interessanten Ergebnissen bei der automatischen Vervollständigung. Während ~fooder automatischen Vervollständigung kann ich bestätigen, dass fooes sich nicht um einen Benutzer auf meinem System handelt (und in der Tat nicht vorhanden ist /etc/passwd). Außerdem werden alle Ordner / Dateien /some/mount/pointin der Autovervollständigung angezeigt, was sehr interessant ist.
RD