¿Qué es un ~ (tilde) cuando se usa como prefijo de una ruta?

11

Editar: Este es un duplicado de /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . No tengo la reputación de cerrar esta pregunta como duplicado.

No me refiero ~como en el directorio de inicio, sino más bien esto:

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

Sin embargo, si lo intento con un punto de montaje diferente, por ejemplo:

$ 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

¿Cómo se ~llama en este contexto? ¿Como funciona?

Editar: más información basada en algunos de los comentarios a continuación:

  1. Puedo dar fe de que foono es un nombre de usuario en mi sistema.
  2. Al intentar completar automáticamente, ls -lah ~no se muestran todas las opciones. es decir, puedo cd ~qux, cuando quxno aparece en el autocompletado. De nuevo quxno es un usuario en mi sistema.
  3. Si importa /some/mount/pointes un recurso compartido de red.
  4. Todos los detalles sugieren alguna ruina de ruta con nombre, una característica de Z shell de expansión de nombre de ruta, pero esto también funciona en bash, que aparentemente no admite cosas como las rutas con nombre de Z shell.
RD
fuente
55
~fooes el directorio de inicio del usuario foo. Si no se especifica el usuario, el usuario actual es el predeterminado.
DopeGhoti
Pero en este caso, /some/mount/pointdefinitivamente no es mi directorio personal. cd ~me lleva a /Users/$username/partidos --que$HOME
RD
1
zshparece utilizar también la tilde para indicar directorios con nombre.
DopeGhoti
Yo también sospechaba eso !! Excepto por alguna razón, la serie de comandos que publiqué anteriormente también funciona en bash ( bash -c "ls ~foo/bar"), que no tiene directorios con nombre. Además, incluso dentro de zsh, si inspecciono el env, no veo ningún directorio con nombre configurado. Estoy en Mac OS y siento que esta es una característica específica de OS X.
RD
1
Solo dijiste ~foo. Tome la cadena real (no el ejemplo foo) y haga grep "actual username" /etc/passwd. ~textdebería funcionar solo para posibles nombres de usuario de inicio de sesión de acuerdo con el manual de bash (no necesariamente significa que realmente pueda iniciar sesión; en el caso de usuarios del sistema como ~lp, por ejemplo). En todas mis pruebas, ~stringcorresponde con stringser nombre de usuario.
Sergiy Kolodyazhnyy

Respuestas:

14

¿Qué es ~ foo

Cita del manual de bash (con énfasis adicional):

Si una palabra comienza con un carácter de tilde sin comillas (`~ '), todos los caracteres que preceden a la primera barra inclinada sin comillas (o todos los caracteres, si no hay una barra inclinada sin comillas) se consideran un prefijo tilde. Si ninguno de los caracteres en el Se prefieren tilde-prefix, los caracteres en el prefijo tilde que siguen a tilde se tratan como un posible nombre de inicio de sesión.

~foo se expande al foodirectorio de inicio del usuario exactamente como se especifica en /etc/passwd. Tenga en cuenta que esto puede incluir nombres de usuario del sistema; no necesariamente significa usuarios humanos o que realmente pueden iniciar sesión localmente (por ejemplo, pueden iniciar sesión a través de claves SSH).

De hecho, como se señaló en los comentarios , bashutilizará la getpwnamfunción. Esa función en sí es especificado por POSIX estándar, por lo tanto, debe existir en más sistemas similares a Unix, incluyendo MacOS X . Esta función no se limita /etc/passwdsolo a búsquedas en otras bases de datos, como LDAP y NIS. Extracto particular del bash código fuente , tilde.carchivo, comenzando en la línea 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;

Ejemplo práctico

A continuación puede ver las pruebas con los nombres de usuario del sistema en mi sistema. Preste atención a la passwdentrada correspondiente y al resultado 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

Incluso si, por ejemplo, la _aptcuenta está bloqueada como lo sugiere la salida passwd -S apt, todavía se muestra como posible nombre de inicio de sesión:

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

Tenga en cuenta: esta no es una característica específica de macOS, sino una característica específica de shell.

Sergiy Kolodyazhnyy
fuente
Dudo que el shell pueda confiar en averiguar algo sobre la fecha de vencimiento de la cuenta o si está bloqueado o algo al expandir la tilde. Por ejemplo, en Linux, la fecha de vencimiento se almacena /etc/shadowjunto con la otra información de autenticación protegida, como la contraseña. La referencia en passwdse trata de invalidar la contraseña: eso no impediría la autenticación por otros medios.
ilkkachu
@ilkkachu Sí, tienes razón. Lo probé agregando testusery modificando la fecha de vencimiento de la contraseña. El nombre de usuario todavía aparece al completar la pestaña. He eliminado esa parte de la respuesta
Sergiy Kolodyazhnyy
1
El único problema con esta respuesta es que cita la bashpágina de manual (al parecer, la anterior). El OP realmente está usando zsh(podría haber sido más claro), aunque en los comentarios se menciona que bashtiene el mismo comportamiento.
Ken Wayne VanderLinde
2
Puede usar en getent passwd foolugar de grep foo /etc/passwordseguir los mismos mecanismos de búsqueda que el shell, tal vez incluyendo servicios de directorio basados ​​en la red que @Abigail menciona.
RJHunter
1
¡Aceptado como respuesta para el bit 'como LDAP y NIS', que terminó siendo correcto en mi caso!
RD
5

En resumen de por qué está viendo algo ~foo/bar, es porque tiene un usuario nombrado fooen el sistema con una carpeta nombrada baren su directorio de inicio.

Vea esta solución en otra comunidad que explica por qué (tilde) ~es más que solo "directorio de inicio".

Si tiene un usuario nombrado binen su sistema, puede enumerar los contenidos del directorio de inicio de bin mediante el comando:

ls ~bin

Otra cosa que puede intentar es usar la finalización de tabulación después de escribir lo siguiente en un indicador (no devuelva el carro, solo use la tecla tab):

ls -lah ~ tab

para ver la lista de directorios de inicio de los usuarios que ~se expandirán si continúa. Ejemplo de salida (truncada) de completar la pestaña dels -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/
WEBjuju
fuente
1
+1 para completar la pestaña. Esto revela claramente todos los nombres de usuario que bash puede obtener como posibles nombres de inicio de sesión /etc/passwd. Inmediatamente ayuda a aclarar qué sucede si el usuario, por supuesto, conoce los nombres de usuario que tiene en el sistema.
Sergiy Kolodyazhnyy
2
Gracias por el consejo sobre la finalización de bash, que resultó en algunos resultados de autocompletado interesantes. Si bien se ~foocompletó automáticamente, puedo dar fe de que foono es un usuario en mi sistema (y de hecho no existe /etc/passwd). Además, todas las carpetas / archivos /some/mount/pointaparecen en el autocompletado, lo cual es muy interesante.
RD