¿La tilde, `~` se considera un camino relativo?

35

Estoy tratando de extraer la parte diferente del instalador de la biblioteca Nvidia cuda. Estoy usando el siguiente comando:

mkdir ~/Downloads/nvidia_installers
./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers

Y recibo el siguiente mensaje:

ERROR: extract: path must be absolute.

Y cuando escribo el comando con la dirección literal de mi casa, funciona perfectamente.

./cuda_6.5.14_linux_64.run -extract=/home/likewise-open/XXX/username/Downloads/nvidia_installers

Estoy confundido, ¿no debería ~ ser el mismo de / home / likewise-open / XXX / username?

Probado:

./cuda_6.5.14_linux_64.run -extract=$HOME/Downloads/nvidia_installers

y funciona, pero no sé por qué no permite ~

Regan
fuente
2
Relacionado: "Un" prefijo tilde "consiste en un carácter <tilde> sin comillas al comienzo de una palabra, seguido de todos los caracteres que preceden al primer sin comillas"
Braiam

Respuestas:

47

Bash solo expande un ~ si es el comienzo de una palabra. Puede ver esto entre los siguientes comandos:

$ echo -extract=~/test
-extract=~/test

oli@bert:~$ echo -extract ~/test
-extract /home/oli/test

Bash busca ~personajes independientes y ~/esta sustitución. Ninguna otra combinación o versión citada funcionará.

$HOMEfunciona porque las sustituciones variables son más robustas ( $es un carácter especial, mientras que ~es mucho menos):

$ echo Thisisastring${HOME}awrawr
Thisisastring/home/oliawrawr

Mientras hablamos ~, en realidad tiene otros dos usos de sustitución:

  • ~+el directorio de trabajo actual (leer de $PWD)
  • ~-el directorio de trabajo anterior (leer de $OLDPWD)

Al igual que con plain ~, estos pueden tener rutas adicionales agregadas al final, y nuevamente, estos deben ser el prefijo de una palabra o Bash los ignorará.

Puedes leer más sobre esto en man bash | less -p ' Tilde'

Oli
fuente
2
Vale la pena señalar que zsh qué (o más bien puede ser configurado para) Expand ~después =también. Entre otras mejoras convenientes que tiene sobre bash.
Jan Hudec
@ JanHudec No, es más complicado; No se trata de expandirse después =; se trata de expandir al comienzo del lado derecho de una asignación variable. Eso hace que nuestro caso sea un poco más confuso al mirar de cerca: vea mi respuesta. Y zshno es diferente de bashesto; La descripción de 'zsh' es un poco críptica: info --subnodes zsh | less +/'14.7.4 Notes'(faltan páginas de manual de zsh)
Volker Siegel
1
@VolkerSiegel: zshes muy configurable. En mi zsh echo -extract=~/testresulta en -extract=/home/user/test. Está habilitado por MAGIC_EQUAL_SUBSTopciones. En una nota al margen, tengo todas las páginas de manual de zsh muy bien.
Jan Hudec
@ JanHudec No hay duda de que zshes configurable y otras mejoras; Hubiera esperado que MAGIC_EQUAL_SUBST (cubierto en 14.7.4) no esté configurado de forma predeterminada y rara vez se use; Ahora, obviamente, es más relevante si lo tiene habilitado en general. Después de que mi sección de ejemplo esté en buena forma, sería una buena adición ...
Volker Siegel
@JanHudec Con respecto a las páginas de manual de zsh, faltaban en los paquetes de Ubuntu por un tiempo, gracias por la sugerencia, no sabía que se había solucionado; Mirando el error, se solucionó por utópico, pero no confiable, ¡eso lo explica! ( launchpad: faltan todas las páginas de manual de zsh y los archivos de ayuda en línea y AU: falta el hombre de zsh ... )
Volker Siegel
19

Solo arreglándolo

Este comando muestra un mensaje de error "ERROR: extract: la ruta debe ser absoluta":

./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers

El error no es útil: el programa ya estaba demasiado confundido.
Ya sabes que el error proviene de ~, ya que funciona con él $HOME.

El problema: ~solo se reemplaza al comienzo de una palabra.

Por ejemplo, esto funciona con la tilde:

echo -extract ~/Downloads

Si necesita la sintaxis de la opción con =, usar $ HOME en lugar de ~es la solución más limpia;

echo -extract=$HOME/Downloads

La práctica

Lo que deberías saber:

Hay casos especiales donde ~get's se expande cuando no está al principio de una palabra: como parte de una asignación variable, directamente después de =. Lo cual es confuso aquí, por supuesto.

El otro caso especial importante es su uso con variables como PATH. En asignaciones variables, ~también se expande después :, como después de la primera =.

$ dir=~ sh -c 'echo D2: $dir'
D2: /home/user
$ sh -c 'echo D2: $dir' dir=~
D2: 
$ echo Dir: $dir
Dir:
$ dir=~; sh -c 'echo D2: $dir'
D2: 
$ echo Dir: $dir
Dir: /home/user
$ sh -c 'echo D2: $dir'; d3=~
D2: 
$ echo d3: $d3
d3: /home/user

El significado de la tilde

En una concha, ~la tilde, no es realmente un camino. Solo se reemplaza por un camino $HOME, algunas veces.

Es algo así como una abreviatura, o abreviatura, proporcionada por el shell.
No se puede usar como una ruta en general, el shell "lo expande" a una ruta solo en lugares muy especiales.
E incluso si se expande, puede ser algo más que el directorio de inicio.

  • Solo se expande al comienzo de una palabra , o en una asignación variable después de un :o=
  • Solo se expande si no está entre comillas
  • Solo se expande a $HOMEsi no hay más caracteres en la palabra antes de un/

El problema en la linea de comando

De acuerdo con esto, el problema en su comando es que la tilde en

-extract=~/Downloads/nvidia_installers

no se expande porque no es uno de los casos enumerados. Eso es todo.

La solución podría ser hacer que la tilde sea el primer carácter sin comillas de una palabra, sin otro carácter antes de la siguiente /; eso es justo lo que obtienes cuando usas una opción con un espacio antes del argumento de la opción:

-extract ~/Downloads/nvidia_installers

Otra solución sería usar $HOMEen su lugar. En un guión, esa suele ser la mejor opción.

-extract=$HOME/Downloads/nvidia_installers

El mensaje de error

Pero, ¿cómo aparece el mensaje de error
"ERROR: extract: path must be absolute."?
encajar en todo esto?

Sabemos que la tilde no se expandió. Eso significa que el programa obtuvo el texto del argumento incluyendo el ~, pero sin el /home/ausercomo la ruta. Ese camino es ~/Downloads/nvidia_installers, pero ahora no hay caparazón, por lo que la tilde no tiene un significado especial. Es solo un nombre de directorio normal. Y como cualquier otra ruta de la forma foo/bar/baz, es una ruta relativa

Otros usos

Si hay caracteres después de ~, como en ~alice- con todas las demás reglas anteriores aplicadas - y hay un nombre de usuario alice, que se expande al directorio de inicio de alice, digamos home/alice.
Además, si es así bob, ~se expandiría a /home/bob, y ~bobse expandiría a la misma.

La variante ~+se expande al directorio actual,$PWD

Para referirse al directorio anterior, donde estaba antes del último cd, puede usar ~-, que se expande a $OLDPWD.

Si usa pushdy popd, en lugar de cd, ya sabrá que se puede acceder a la pila de directorios como ~-2.

Detalles

Todos los casos donde ~se expande a una ruta son manejados por el shell . Para otros programas, ~es solo un carácter de nombre de archivo normal.

Para la definición exacta dentro del shell, aquí está la sección relevante de Note cómo reemplazar por es solo un caso especial de muchos casos: "Si este nombre de inicio de sesión es la cadena nula, la tilde se reemplaza con el valor del parámetro del shell HOME. " :man bash
~$HOME

Tilde Expansion
    If a word begins with an unquoted tilde character (`~'), all of the charac‐
    ters  preceding the first unquoted slash (or all characters, if there is no
    unquoted slash) are considered a tilde-prefix.  If none of  the  characters
    in  the tilde-prefix are quoted, the characters in the tilde-prefix follow‐
    ing the tilde are treated as a possible login name.  If this login name  is
    the  null string, the tilde is replaced with the value of the shell parame‐
    ter HOME.  If HOME is unset, the home directory of the user  executing  the
    shell is substituted instead.  Otherwise, the tilde-prefix is replaced with
    the home directory associated with the specified login name.

    If the tilde-prefix is a `~+', the value of the shell variable PWD replaces
    the  tilde-prefix.   If  the tilde-prefix is a `~-', the value of the shell
    variable OLDPWD, if it is set, is substituted.  If the characters following
    the tilde in the tilde-prefix consist of a number N, optionally prefixed by
    a `+' or a `-', the tilde-prefix is replaced with the corresponding element
    from  the  directory  stack,  as  it would be displayed by the dirs builtin
    invoked with the tilde-prefix as an argument.  If the characters  following
    the  tilde in the tilde-prefix consist of a number without a leading `+' or
    `-', `+' is assumed.

    If the login name is invalid, or the tilde expansion  fails,  the  word  is
    unchanged.

    Each variable assignment is checked for unquoted tilde-prefixes immediately
    following a : or the first =.  In these cases, tilde expansion is also per‐
    formed.   Consequently, one may use filenames with tildes in assignments to
    PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.
Volker Siegel
fuente
3

~No es un camino per se. Es un personaje que recibe un tratamiento especial del shell donde ~o ~/significa "reemplazar con la ruta del directorio de inicio del usuario actual". ~usernamesignifica "reemplazar con la ruta del directorio de inicio del nombre de usuario".

Debido a que no es una ruta, solo se reconoce en ciertos lugares del comando (como el primer carácter de una nueva ficha dividida en espacio).

Cuando se expande, se reemplaza con una ruta absoluta.

El uso $HOMEfunciona porque HOME es solo una variable establecida por el shell y sigue las reglas normales del shell para el reemplazo de variables (ocurre antes de que la entrada se divida en espacios y se ejecute).

Daenyth
fuente
1

Estás en lo correcto. ~ / Downloads es lo mismo que / home / username / Downloads.

Algunos instaladores y extractores son muy exigentes con respecto a dónde necesita colocar las cosas. Creo que podría ser porque registra las rutas de los archivos, y los registros no aceptarán ~ en una ruta aceptada.

Solo me acostumbré a escribir / home / username en su lugar. :)

Dan Johansen
fuente