Como escapar corretamente dos pontos de exclamação no bash?

11

Hoje, fui pego em flagrante enquanto tentava codificar no golfe um gerador de senhas para o Twitter.

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

90 caracteres. Como isso é muito espaço livre, decidi elevar a fasquia e torná-la executável também.

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. Bom, exceto que obviamente o bash engasga com o ponto de exclamação.

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

Ponto de exclamação traquina. "Vamos fugir", pensei! Eu tenho um personagem sobressalente, afinal.

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))

Deixando meu código estúpido de lado - não posso explicar isso.

Com \!, o ponto de exclamação foi escapado, exceto que realmente não era, porque o \!foi deixado como é para echopegar.

Uma solução poderia estar sendo usada \x21, mas não estou convencido de que seja a maneira correta de escapar de um ponto de exclamação em um comando bash.

tl; dr: Como você escapa corretamente um ponto de exclamação em um comando bash?

badp
fonte
Alguém realmente usa a !eventsintaxe em primeiro lugar? Sempre me causou apenas problemas.
badp

Respostas:

7

Use aspas 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

As regras para !foram meio que enxertadas nas outras regras de citação posteriormente (do csh). Eles eram muito úteis quando os shells não tinham edição de linha de comando, mas algumas pessoas ainda os usam agora.

PS Como você está codificando para o 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

Isso funciona na maioria das 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

(Não que eu entenda por que você deseja criar um script ou por que o nome do script deve ter duas letras.)

Gilles 'SO- parar de ser mau'
fonte
Não sabia $''. :) PS: Era para tentar usar esses caracteres extras. Sinto um desperdício ao publicar tweets com menos de 140 caracteres.
18710 badp
@badp: Portanto, tente gerar senhas memoráveis . (Como no pwgenvs. pwgen -s).
Gilles 'SO- stop be evil'
Poderia muito bem usar dadadodo para senhas memoráveis, mas sem sentido, em seguida :) :)
badp
1

Eu deveria ter pesquisado no Google antes de perguntar.

Como você não depende do bash para expandir variáveis ​​[..], você pode usar aspas simples. Cadeias de caracteres entre aspas simples não são expandidas pelo bash.

honk em resposta a Como faço para escapar de um ponto de exclamação?

badp
fonte
1
Não estou marcando essa resposta como aceita, no entanto, porque responde apenas a esse caso específico. Geralmente, você não pode se safar sem expansão.
Bad