O que é "-bash:!": Evento não encontrado "

114

Tente executar o seguinte em um shell bash echo "Reboot your instance!"

Na minha instalação:

root@domU-12-31-39-04-11-83:/usr/local/bin# bash --version
GNU bash, version 4.1.5(1)-release (i686-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@domU-12-31-39-04-11-83:/usr/local/bin# uname -a
Linux domU-12-31-39-04-11-83 2.6.35-22-virtual #35-Ubuntu SMP Sat Oct 16 23:57:40 UTC 2010 i686 GNU/Linux
root@domU-12-31-39-04-11-83:/usr/local/bin# echo "Reboot your instance!"
-bash: !": event not found

Alguém por favor pode explicar o que é "eventos de festa"? Eu nunca ouvi esse conceito antes. Além disso, como devo gerar "!" no final da frase?

Maxim Veksler
fonte

Respostas:

53

Você pode desativar a substituição do histórico usando set +H.

Dennis Williamson
fonte
2
Você conhece o raciocínio por trás da sintaxe? Parece realmente contra-intuitivo. Você pensaria que digitaria +Hpara ativar e -Hdesativar algo.
Gavin Ward
7
@PunkyGuy: Não conheço a história (trocadilhos), mas as opções do Unix geralmente começam com um hífen (ou menos) e +são simplesmente o oposto disso.
Dennis Williamson
105

!é um caractere especial para bash, é usado para se referir a comandos anteriores; por exemplo,

!rm

irá chamar e executar o último comando que começou com a cadeia "rm" e

!rm:p

lembrará, mas não executará o último comando iniciado com a string "rm". bash está interpretando o ponto de exclamação echo "reboot your instance!"como " substitua aqui o último comando que começou com o (s) caractere (s) imediatamente após o ponto de exclamação " e resmunga que não consegue encontrar um evento (comando) no seu histórico que comece com um único citação dupla.

Experimentar

echo reboot your instance\!

para proteger (escapar) o ponto de exclamação do bash.

Chapeleiro Louco
fonte
Sim, mas deve acontecer se eu quiser usar echo -e "algum texto $ ENV_VAL mais algum texto \ nReinicie agora!" ?
Maxim Veksler /
1
Escreva duas instruções de eco; você obtém o avanço de linha gratuitamente.
MadHatter
1
A solução simples é usar aspas simples e aspas duplas de uma só vez: echo -e "Text \ nReeboot" '!'
mmey
4
Isso é péssimo. Se eu não escapar do ponto de exclamação, o bash fará um ajuste. Se eu fazer escapar, a barra invertida é incluída na string final. Por que você faz isso, Bash !! ( pastebin.com/g4PYv56A )
Hubro 23/01
2
@Hubro com justiça, não tenho certeza se tudo é culpa do bash. Você tem questões um tanto complicadas usando o ruby ​​para alimentar as coisas, e não está claro para mim que papel o rubi está desempenhando na remoção ou no reforço dos caracteres de escape.
MadHatter
25

Para resolver seu problema original, tente usar aspas simples, em vez de aspas duplas. Com o último, o bash tentará expandir certos caracteres antes de passar o resultado para o comando (eco neste caso). Com aspas simples, o bash passa a cadeia inteira, inalterada.

!é usado em comandos para se referir ao histórico da linha de comandos. Consulte: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS para obter um conjunto completo. Com o exemplo acima, o bash está tentando expandir !"como uma referência a um evento antes que o eco seja visto, daí o erro.

Observe que nos scripts, todos os comandos do histórico estão desativados, pois só fazem sentido em um shell interativo.

O único que eu uso regularmente é !$. Ele se expande para o último argumento do comando anterior. É uma abreviação útil em alguns lugares.

SmallClanger
fonte
4
!!preencher o último comando completo digitado é notavelmente útil; particularmente, sudo !!oupfexec !!
jgoldschrafe
2
Também acho o sudo e o pfexec ótimos utilitários, mas não é preciso ser tão entusiasmado.
precisa saber é
$_funciona em mais conchas do que bash e é uma variável adequada, ao contrário !$. (e @LeartS: gostei da falta de emoticons da sua piada
;;
7

Basta colocar um espaço no meio! e "do que vai funcionar.

Felicidades.

Isik Mater
fonte
2
Você poderia adicionar uma explicação sobre por que sua solução funciona?
200_success 26/09/14
2
Isso funciona porque o Bash trata apenas! como um caractere especial se for diretamente seguido por um caractere que não seja um espaço em branco. No entanto, também irá adicionar um extra em branco para a sua saída, de modo que não pode ser sempre desejado ...
mmey
2

Sim, ! é um caractere especial para bash, é usado para se referir a comandos anteriores.

Poucas maneiras de lidar com a situação

A seguir, será exibida a string como está

echo 'Reboot your instance!'

A seguir, o comando será executado e concatenado a sequência

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`
Syed Qaiser
fonte
1

Em bash 4.3parece que você não precisa mais usar aspas simples ou set +H:

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-unknown-linux-gnu)
[...]
$ echo "Reboot your instance!"
Reboot your instance!
Eugene Yarmash
fonte
Provavelmente um bug, porque aqui eu tenho o 4.4.12 e, mais uma vez, preciso set +Hou citar. Ou você tem set +Halgum lugar (como em /etc/profile).
Bodo Thiesen
O uso de! -Char não no final da frase verifica se a detecção de eventos do bash ainda está funcionando bem. Versão é 4.3.30 ........ $ echo bash: foo: evento não encontrado "Verifique novamente sua sentença foo!"!
JohnnyD92
0

Você também pode usar um heredoc :

cat <<EOF
Reboot your instance!
EOF

É irritante neste caso, porque não é uma linha, mas para comandos mais longos (como escrever um script bash), funciona muito bem.

Tom Saleeba
fonte