¿Qué es "-bash:!": Evento no encontrado "

114

Intente ejecutar lo siguiente bajo un shell bash echo "Reboot your instance!"

En mi instalación:

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

¿Alguien puede explicar qué es "bash events"? Nunca he escuchado este concepto antes. Además, ¿cómo debo mostrar "!" al final de la oración?

Maxim Veksler
fuente

Respuestas:

53

Puede desactivar la sustitución del historial con set +H.

Dennis Williamson
fuente
2
¿Conoces el razonamiento detrás de la sintaxis? Parece realmente contrario a la intuición. Pensarías que escribirías +Hpara habilitar algo y -Hpara deshabilitar algo.
Gavin Ward,
77
@PunkyGuy: No sé el historial (juego de palabras previsto) detrás de él, pero las opciones de Unix generalmente comienzan con un guión (o menos) y +es simplemente lo contrario de eso.
Dennis Williamson
105

!es un personaje especial para bash, se usa para referirse a comandos anteriores; p.ej,

!rm

recordará y ejecutará el último comando que comenzó con la cadena "rm", y

!rm:p

recordará pero no ejecutará el último comando que comenzó con la cadena "rm". bash está interpretando el signo de exclamación echo "reboot your instance!"como " sustituir aquí el último comando que comenzó con los caracteres que siguen inmediatamente al signo de exclamación ", y se queja de que no puede encontrar un evento (comando) en su historial que comenzó con un solo doble comilla

Tratar

echo reboot your instance\!

para proteger (escapar) el signo de exclamación de bash.

MadHatter
fuente
Sí, pero debería suceder si quiero usar echo -e "algún texto $ ENV_VAL un poco más de texto \ nReboot now!" ?
Maxim Veksler
1
Escribe dos declaraciones de eco; obtienes el salto de línea gratis.
MadHatter
1
La solución simple es usar comillas simples y comillas dobles a la vez: echo -e "Text \ nReeboot" '!'
mmey
44
Esto apesta. Si no escapo al signo de exclamación, bash lanza un ataque. Si lo escapo, la barra invertida se incluye en la cadena final. ¿Por qué haces esto, Bash! ( pastebin.com/g4PYv56A )
Hubro el
2
@Hubro para ser justos, no estoy seguro de que todo sea culpa de bash. Tienes asuntos un tanto complicados al usar ruby ​​para alimentar cosas para golpear, y no me queda claro qué papel juega ruby ​​en el despojo o refuerzo de los personajes de escape.
MadHatter
25

Para resolver su problema original, intente usar comillas simples, en lugar de comillas dobles. Con este último, bash intentará expandir ciertos caracteres antes de pasar el resultado al comando (echo en este caso). Con comillas simples, bash pasa toda la cadena, sin cambios.

!se usa en los comandos para referirse al historial de la línea de comandos. Consulte: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS para obtener un conjunto completo. Con el ejemplo anterior, bash intenta expandirse !"como referencia a un evento antes de que echo eche un vistazo, de ahí el error.

Tenga en cuenta que en los scripts, todos los comandos del historial están deshabilitados, ya que solo tienen sentido en un shell interactivo.

El único que uso regularmente es !$. Se expande al último argumento del comando anterior. Es una taquigrafía útil en algunos lugares.

SmallClanger
fuente
44
!!completar el último comando ingresado es notablemente útil; particularmente, sudo !!opfexec !!
jgoldschrafe
2
También encuentro que sudo y pfexec son buenas utilidades, pero no es necesario que sea tan entusiasta.
LeartS
$_funciona en más shells que bash y es una variable adecuada, a diferencia de !$. (y @LeartS: Me gustó la falta de emoticones de tu broma.;))
ΤΖΩΤΖΙΟΥ
7

¡Solo pon un espacio entre ellos! y "de lo que funcionará.

Salud.

Isik Mater
fuente
2
¿Podría agregar una explicación de por qué funciona su solución?
200_success
2
¡Esto funciona porque Bash solo trata! como un carácter especial si es seguido directamente por un carácter que no sea un espacio en blanco. Sin embargo, también agregará un espacio en blanco adicional a su salida, por lo que puede que no siempre se desee ...
mmey
2

Si, ! es un carácter especial para bash, se usa para referirse a comandos anteriores.

Pocas maneras de manejar la situación.

Lo siguiente generará la cadena tal como está

echo 'Reboot your instance!'

Lo siguiente ejecutará el comando y concatenará la cadena

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

En bash 4.3lo que parece que ya no es necesario usar comillas simples o 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
fuente
Probablemente sea un error, porque aquí tengo 4.4.12 y una vez más, necesito set +Ho cito. O tienes un set +Hlugar (como en /etc/profile).
Bodo Thiesen
El uso de! -Char no al final de la oración verifica que la detección de eventos de bash sigue funcionando bien. La versión es 4.3.30 ........ $ echo "¡Vuelva a verificar su oración! Foo" bash
:!
0

También podría usar un heredoc :

cat <<EOF
Reboot your instance!
EOF

Es molesto en este caso porque no es de una sola línea, pero para comandos más largos (como escribir un script bash), funciona muy bien.

Tom Saleeba
fuente