¿Cómo escapar correctamente de los signos de exclamación en bash?

11

Hoy, me sorprendieron con las manos en la masa mientras intentaba codificar un generador de contraseñas para Twitter.

import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))

90 caracteres Como eso es mucho espacio libre, decidí subir el listón y hacerlo ejecutable también.

echo -e "#!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg

139 caracteres. Agradable, excepto que obviamente se atraganta con el signo de exclamación.

badp@delta:~$ echo -e "#!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg
bash: !/usr/bin/python\nimport: event not found

Signo de exclamación molesto. "Vamos a escapar", pensé! Tengo un personaje extra después de todo.

echo -e "#\!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg

Obviamente...

badp@delta:~$ echo -e "#\!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg
./pg: line 2: syntax error near unexpected token `('
./pg: line 2: `import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))'
badp@delta:~$ cat pg
#\!/usr/bin/python
import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))

Dejando a un lado mi código tonto jugando al golf, no puedo explicar esto.

Con \!, el signo de exclamación se escapó, excepto que realmente no lo fue, porque \!se dejó como está para echoque lo recoja.

Una solución podría haber estado usando en su \x21lugar, pero no estoy convencido de que sea la forma correcta de escapar de un signo de exclamación en un comando bash.

tl; dr: ¿Cómo escapas correctamente de un signo de exclamación en un comando bash?

badp
fuente
¿Alguien realmente usa la !eventsintaxis en primer lugar? Siempre me ha causado solo problemas.
badp
Lo uso casi a diario (durante la mayoría de los últimos 20 años) !:0 !$y !^ahorro mucho tiempo y escribiendo.
Alexx Roche

Respuestas:

7

Use comillas simples:

echo -e '#!/usr/bin/python\nimport string as s,random;print "".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg

Las reglas para !fueron injertadas en las otras reglas de citas después (de csh). Eran muy útiles cuando los shells no tenían edición de línea de comando, pero algunas personas todavía los usan ahora.

PD: Ya que estás codificando para bash:

echo $'#!/usr/bin/python\nimport string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg

Esto funciona en la mayoría de las unidades:

echo python -c \''import string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'\'>pg;chmod +x pg;./pg

(No es que entienda por qué quiere crear un guión o por qué el nombre del guión debe ser dos letras).

Gilles 'SO- deja de ser malvado'
fuente
No sabía sobre $''. :) PD: Fue para tratar de usar esos caracteres sobrantes. Tengo una sensación de desperdicio cuando publico tweets de menos de 140 caracteres.
badp
@badp: Intenta hacer que genere contraseñas memorables . (Como en pwgenvs. pwgen -s)
Gilles 'SO- deja de ser malvado'
También podría usar dadadodo para frases de contraseña memorables pero sin sentido, entonces :)
badp
1

Debería haber buscado en Google antes de preguntar.

Dado que no depende de bash para expandir las variables [..], puede utilizar comillas simples en su lugar. Las cadenas entre comillas simples no se expanden con bash.

toque la bocina en respuesta a ¿Cómo escapo de un signo de exclamación?

badp
fuente
1
Sin embargo, no estoy marcando esta respuesta como aceptada, porque solo responde a este caso específico. En general, no puedes escaparte sin expansión.
badp