¿Por qué la tilde (~) no se expande dentro de comillas dobles?

54

Según esta respuesta y mi propio entendimiento, la tilde se expande al directorio de inicio:

$ echo ~
/home/braiam

Ahora, cada vez que quiera que funcione la expansión de shell, es decir, usando nombres de variables como $FOO, y no se rompan debido a caracteres inesperados, espacios, etc., uno debe usar comillas dobles ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

¿Por qué esta expansión no funciona con la tilde?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
fuente
3
También tenga en cuenta que esto tiene la inconsistencia al proporcionar un argumento del programa en la línea de comando que en el argumento del comando se --path ~/myfileexpande pero --path=~/myfileno lo hace.
Ángel
Relacionado: ~ siempre es igual a $ HOME
Stéphane Chazelas
Una variación de este tema es unix.stackexchange.com/questions/279565 .
JdeBP

Respuestas:

45

La razón, porque dentro de las comillas dobles, tilde ~no tiene un significado especial, se trata como literal.

POSIX define comillas dobles como:

Los caracteres encerrados entre comillas dobles ("") conservarán el valor literal de todos los caracteres dentro de las comillas dobles, con la excepción del signo de dólar, la comilla y la barra invertida de los caracteres,

...

La aplicación se asegurará de que una comilla doble esté precedida por una barra diagonal inversa que se incluirá dentro de las comillas dobles. El parámetro '@' tiene un significado especial dentro de las comillas dobles

Excepto $, `, \y @, otros personajes son tratados como comillas dobles dentro de literales.

Cuonglm
fuente
99
En cuyo caso, supongo que deberías usar $HOME.
Seth
11
O simplemente no puede citar ~, por ejemplols -l ~/"My Documents"
Andrew Medico
Esto es muy poco intuitivo. ¿Cuál es la razón por la que eligieron hacer esto? (Esta respuesta en realidad no da la razón, sino que solo apunta al estándar, pero presumiblemente el estándar fue escrito de esa manera por una razón )
Iconoclasta
1
@iconoclast si realmente quieres un "por qué se implementaron de esta manera", lee la respuesta de Stephane .
Braiam
2
Así, @iconoclast, ¿por qué es azul el cielo? :) :) :)
Jesse Chisholm
32

La expansión de Tilde se define por POSIX como:

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 <slash> sin comillas en la palabra, o todos los caracteres en la palabra si no hay < barra oblicua>. En una asignación, se pueden usar múltiples prefijos de tilde: [...] siguiendo el <equals-sign> de la asignación, siguiendo cualquier <colon> sin comillas, o ambos. [...] Si ninguno de los caracteres en el prefijo tilde se cita, los caracteres en el prefijo tilde después de <tilde> se tratan como un posible nombre de inicio de sesión de la base de datos de usuarios. [...] Si el nombre de inicio de sesión es nulo (es decir, el prefijo tilde contiene solo la tilde), el prefijo tilde se reemplaza por el valor de la variable HOME. Si HOME no está configurado, los resultados no están especificados. [...]

Entonces, la respuesta más corta es "porque se define de esa manera": al citar cualquiera de los caracteres del prefijo, incluido el ~, se suprime la expansión.

También define la expansión como siempre dando como resultado una sola palabra, por lo que sería innecesario citar:

El nombre de ruta resultante de la expansión de tilde se tratará como si fuera citado para evitar que sea alterado por la división de campo y la expansión de nombre de ruta.

Cuando algunas de las rutas requieren comillas, pero el resto es un prefijo de tilde, puede combinar la expansión de tilde y las comillas ordinarias directamente:

$ cat ~/"file name with spaces"

En el "por qué" más amplio: dado que no hay un uso concebible para la división de palabras ~, ese debería ser el comportamiento predeterminado, en lugar de requerir que se cite. Como no es necesario citarlo, dar ~un significado especial dentro de las comillas sería una complicación innecesaria. Y, por supuesto, las razones históricas significan que no se podría cambiar ahora, incluso si eso fuera deseable.

Michael Homer
fuente
Según esta guía de bash , la expansión de tilde ocurre antes de la separación de espacios en blanco. ¿Hay alguna manera de hacer una expansión de tilde de forma segura, incluso si su directorio de inicio tiene espacios en blanco? Normalmente, por supuesto, harías este tipo de cosas con "".
Lucretiel
La expansión es una sola palabra; vea el segundo pasaje citado en la respuesta.
Michael Homer
23

~ se origina en el shell C, mucho antes de que se agregue al shell Korn y luego se agregue a la especificación del shell POSIX.

En el C-shell, ~era un operador global (expandido por la misma rutina que la que se expande, *.txtpor ejemplo), por lo que al igual que el resto del global no se realizó entre comillas dobles.

Stéphane Chazelas
fuente
11

Si bien esto no responde por qué está diseñado de esa manera, en su $HOMElugar lo usa si necesita sustituirlo, ya que eso es esencialmente lo que ~hace.

$ echo "$HOME/some/path"
/home/braiam/some/path
fusiones
fuente
66
esto no funciona con~otheruser
Johannes Kuhn
2
Es cierto, pero podría hacer: ELLOS = ~ otro usuario y luego usar "$ ELLOS / algunos / ruta"
fusiona el
1
La solución alternativa ~otherusermuestra qué mala idea era tratar de manera ~diferente a las variables y otras cosas que se expanden entre comillas dobles.
iconoclasta