Qu'est-ce qu'un ~ (tilde) lorsqu'il est utilisé comme préfixe d'un chemin?


11

Modifier: Il s'agit d'un doublon de /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . Je n'ai pas la réputation de fermer cette question en double.

Je ne fais pas référence à ~comme dans le répertoire personnel mais plutôt à ceci:

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

Cependant, si je le tente avec un point de montage différent, par exemple:

$ 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

Comment ~s'appelle dans ce contexte? Comment ça marche?

Modifier: Plus d'informations basées sur certains des commentaires ci-dessous:

  1. Je peux attester que ce foon'est pas un nom d'utilisateur sur mon système.
  2. Lors de la tentative de saisie semi-automatique, ls -lah ~toutes les options ne sont pas affichées. c'est-à-dire que je peux cd ~qux, quand quxn'apparaît pas dans la saisie semi-automatique. Encore quxune fois, ce n'est pas un utilisateur dans mon système.
  3. Si c'est important, /some/mount/pointc'est un partage réseau.
  4. Tous les détails suggèrent un muckery de chemin nommé, une caractéristique du shell Z de l'expansion du nom de chemin, mais cela fonctionne également dans bash, qui ne supporte apparemment pas des choses comme les chemins nommés du shell Z.

5
~fooest le répertoire personnel de l'utilisateur foo. Si l'utilisateur n'est pas spécifié, l'utilisateur actuel est celui par défaut.
DopeGhoti

Mais dans ce cas, ce /some/mount/pointn'est certainement pas mon répertoire personnel. cd ~m'emmène à /Users/$username/--quels matchs$HOME
RD

1
zshsemble également utiliser le tilde pour indiquer les répertoires nommés.
DopeGhoti

Je m'en doutais aussi !! Sauf pour une raison quelconque, la série de commandes que j'ai postée ci-dessus fonctionne également dans bash ( bash -c "ls ~foo/bar") - qui n'a pas de répertoires nommés. De plus, même dans zsh, si j'inspecte le env, je ne vois aucun répertoire nommé configuré. Je suis sur Mac OS et je pense que c'est une fonctionnalité spécifique à OS X.
RD

1
Tu as seulement dit ~foo. Prenez la chaîne réelle (pas l'exemple foo) et faites grep "actual username" /etc/passwd. ~textne devrait fonctionner que pour les noms d'utilisateur de connexion possibles selon le manuel bash (ne signifie pas nécessairement qu'il est réellement capable de se connecter; dans le cas d'utilisateurs du système tels que ~lp, par exemple). Dans tous mes tests, le ~stringcorrespond à stringêtre nom d'utilisateur.
Sergiy Kolodyazhnyy

Réponses:


14

Qu'est-ce que ~ foo

Citation du manuel bash (avec un accent supplémentaire):

Si un mot commence par un caractère tilde sans guillemets (`~ '), tous les caractères précédant la première barre oblique sans guillemets (ou tous les caractères, s'il n'y a pas de barre oblique sans guillemets) sont considérés comme un préfixe tilde.Si aucun des caractères de la le préfixe tilde est cité, les caractères dans le préfixe tilde suivant le tilde sont traités comme un nom de connexion possible .

~foo se développe dans foole répertoire personnel de l'utilisateur exactement comme spécifié dans /etc/passwd. Notez que cela peut inclure des noms d'utilisateur système; cela ne signifie pas nécessairement des utilisateurs humains ou qu'ils peuvent réellement se connecter localement (ils peuvent se connecter via des clés SSH par exemple).

En fait, comme indiqué dans les commentaires , bashutilisera la getpwnamfonction. Cette fonction lui - même est spécifiée par POSIX standard, devrait donc exister dans la plupart des systèmes Unix, y compris macOS X . Cette fonction n'est pas limitée à /etc/passwdseulement et recherche d'autres bases de données, telles que LDAP et NIS. Extrait particulier du bash code source , tilde.cfichier, à partir de la ligne 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;

Exemple pratique

Ci-dessous, vous pouvez voir les tests avec les noms d'utilisateur du système sur mon système. Faites attention à l' passwdentrée correspondante et au résultat dels ~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

Même si, par exemple, le _aptcompte est verrouillé comme suggéré par la sortie, passwd -S aptil apparaît toujours comme nom de connexion possible:

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

Remarque: ce n'est pas une fonctionnalité spécifique à macOS, mais plutôt une fonctionnalité spécifique au shell.


Je doute que le shell puisse s'appuyer sur la découverte de la date d'expiration du compte ou s'il est verrouillé ou quoi que ce soit lors de l'expansion du tilde. Par exemple, sous Linux, la date d'expiration est stockée dans /etc/shadow, avec les autres informations d'authentification protégées, comme le mot de passe. La référence dans passwdest juste de rendre le mot de passe invalide: cela n'empêcherait pas l'authentification par d'autres moyens.
ilkkachu

@ilkkachu Oui, vous avez raison. J'ai testé cela en ajoutant testuseret en modifiant la date d'expiration du mot de passe. Le nom d'utilisateur apparaît toujours à la fin de l'onglet. J'ai supprimé ce morceau de la réponse
Sergiy Kolodyazhnyy

1
Le seul problème avec cette réponse est qu'elle cite la bashpage de manuel (et la plus ancienne, semble-t-il). L'OP utilise actuellement zsh(aurait pu être plus clair), bien que dans les commentaires, il soit mentionné qu'il basha le même comportement.
Ken Wayne VanderLinde

2
Vous pouvez utiliser getent passwd fooau lieu de grep foo /etc/passwordpour suivre les mêmes mécanismes de recherche que le shell - peut-être y compris les services d'annuaire basés sur le réseau mentionnés par @Abigail.
RJHunter

1
Accepté comme réponse pour le bit 'tels que LDAP et NIS', qui a fini par être correct dans mon cas!
RD

5

En résumé, pourquoi vous voyez quelque chose ~foo/bar, c'est parce que vous avez un utilisateur nommé foosur le système avec un dossier nommé bardans son répertoire personnel.

Voir cette solution dans une autre communauté qui explique pourquoi (tilde) ~est plus qu'un simple "répertoire personnel".

Si vous avez un utilisateur nommé binsur votre système, vous pouvez lister le contenu du répertoire personnel de bin par la commande:

ls ~bin

Une autre chose que vous pouvez essayer est d'utiliser la complétion de tabulation après avoir tapé ce qui suit à l'invite (ne retournez pas le chariot, utilisez simplement la touche tabulation):

ls -lah ~ tab

pour voir la liste des répertoires personnels des utilisateurs qui ~se développeront si vous continuez. Exemple de sortie (tronquée) de la fin de tabulation dels -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/

1
+1 pour l'achèvement de l'onglet. Cela révèle clairement tous les noms d'utilisateurs que bash peut obtenir comme noms de connexion possibles /etc/passwd. Cela aide immédiatement à clarifier ce qui se passe si l'utilisateur est bien sûr au courant des noms d'utilisateur qu'il a sur le système.
Sergiy Kolodyazhnyy

2
Merci pour l'astuce sur l'achèvement de bash - a donné lieu à des résultats de saisie semi-automatique intéressants. Bien ~fooque la saisie semi-automatique ait été effectuée, je peux attester que ce foon'est pas un utilisateur sur mon système (et en effet n'existe pas dans /etc/passwd). De plus, tous les dossiers / fichiers /some/mount/pointapparaissent dans la saisie semi-automatique, ce qui est super intéressant.
RD
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.