En bash, ¿cómo puedo escapar de un signo de exclamación?

183

Quiero hacer algo así bzr commit -m "It works!". Puedo escapar del signo de exclamación haciendo algo bzr commit -m "It works\!". Sin embargo, mi mensaje de confirmación incluye la barra diagonal inversa. ¿Cómo escapo el signo de exclamación, mientras sigo ignorando la barra invertida?

Mateo
fuente
1
Haciendo bzr commit -m "It works"!trabajos también.
kba
1
Como señalé antes, el comando que pones realmente funciona por sí solo :)bzr commit -m "It works!"
h4unt3r
Un caso aún más peculiar con citas anidadas: stackoverflow.com/questions/22125658/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Aunque la respuesta aceptada es una buena solución para sus problemas de confirmación, creo que no es una respuesta al problema real: la expansión del historial de Bash . ¿Por favor considera aceptar la respuesta de Dennis?
Arjan

Respuestas:

153

Como no depende de bash para expandir las variables en su mensaje de confirmación, puede usar comillas simples en su lugar. Las cadenas entre comillas simples no se expanden con bash.

bzr commit -m 'This does work!' 
Benjamin Bannier
fuente
24
Dado que la pregunta era "¿Cómo puedo escapar de un signo de exclamación?" y no "¿Cómo no amplío un signo de exclamación?" No creo que esto sea válido. Algunas veces (como al pasar apóstrofes y signos de exclamación en la misma línea de comando) esto no funciona. La respuesta a continuación funciona mucho mejor para hacer lo que mucha gente necesita.
Jann
77
@ Janan: Tienes 100% de razón en esto, pero creo que el problema aquí es el que tiene tantas preguntas sobre el superusuario: ¿Respondemos la pregunta al punto o ayudamos a las personas a resolver su problema específico? Creo que ambas formas pueden ser útiles, y esto buscaba ayuda sobre un tema específico.
Benjamin Bannier
touché! Este era un problema específico. Solo tiendo a querer una respuesta a mis preguntas para poder usarla en muchas situaciones. pS: La razón por la que incluso mencioné esto fue porque necesitaba pasar un apóstrofe y un signo de exclamación a un programa perl y necesitaba la solución a continuación. :)
Jann
Estoy de acuerdo con Benjamin y Jann pero di un voto negativo. El título de la pregunta está indexado por los motores de búsqueda y así es como llegué aquí y probablemente la mayoría de los usuarios vengan aquí. Por eso creo que es importante que la pregunta real refleje el problema detrás de esto. En otros foros, se aconseja a las personas (casi obligadas) que pregunten con precisión qué buscan. Responder preguntas mal expresadas respalda la descuido y esa es la razón exacta de mi voto negativo aquí. Como compromiso / solución, mi sugerencia es ayudar a adaptar el encabezado para que refleje el problema real.
ChristophK
153

Aquí hay otro método si desea comillas dobles y la exclamación:

echo "It's broken"'!'

Esto funciona incluso si !no está al final de la línea.

Por ejemplo:

echo "hello there"'!'" and goodbye"

Bonificación: se puede usar una técnica similar para escapar de cualquier texto en Sh o Bash (con la ayuda de sed): vea la primera opción en esta respuesta . Además, si ha bash-completioninstalado, es probable que ya tenga la quote()función disponible.

jwd
fuente
44
Buen consejo, JWD. No me di cuenta de que las cadenas de bash podrían concatenarse simplemente omitiendo espacios en blanco entre ellas.
Alan H.
En realidad, si el signo de exclamación está al final de la cadena que está en el claro echo "Happy birthday!", funcionará como se esperaba, de lo contrario, puede escapar con una barra invertida, pero la barra invertida también se imprimirá XD Bash no es para los débiles :)
h4unt3r
@ h4unt3r: Extraño, esa no es mi experiencia. Para mí, echo "Happy Birthday!"salidas 2 líneas. El primero es echo "Happy birthday"(sin exclamación), y el segundo es "Feliz cumpleaños" (nuevamente, sin exclamación). ¿Tiene activada la expansión del historial cuando realiza esta prueba?
jwd
@jwd ¿qué versión de bash estás ejecutando? Siempre tengo hist expansión en. ¿Usaste accidentalmente dos! para tu prueba?
h4unt3r
@ h4unt3r: version 4.1.2(1)-release (x86_64-redhat-linux-gnu)definitivamente solo se !está utilizando uno . Tengo histexpandpresente en $SHELLOPTS. Sin embargo, acabo de probar la versión 4.3.18 (2) en otra máquina, y se comporta como lo describiste. Supongo que fue un error que se solucionó.
jwd
66

Desactiva la expansión del historial :

set +H

o

set +o histexpand

Puede agregar uno de esos comandos a su ~/.bashrcsi generalmente no usa la expansión del historial.

Bash 4.3 agregó un caso especial :

el carácter de expansión del historial también se trata como citado si precede inmediatamente a la comilla doble de cierre en una cadena entre comillas dobles

Dennis Williamson
fuente
Gracias, esto funcionó, pero tuve que hacerlo set +o histexpand, no set -o histexpand. ¿Podrías editar tu respuesta para arreglar esto?
Mateo
Vaya, error tipográfico, lo siento. Fijo.
Dennis Williamson
excelente! estaba buscando esto para EDADES ... gracias vm! como escape no funcionará ... No quiero usar comillas simples también ... ¡¡¡Agregaré esto a mi .bashrcthx !!, nunca usado !en scripts y para nada !! siempre fue preocupante ...
Aquarius Power
¡Esto es genial! echo "@AquariusPower!"
joehanna
12

Use comillas simples (') en lugar de comillas dobles ("). Las comillas simples desactivan toda interpretación de las cosas en ellas, mientras que las comillas dobles solo desactivan algunas.

bzr commit -m 'It works!'
KeithB
fuente
4

Acabo de encontrar otra forma, que al menos funcionará con echocadenas (oraciones) que desea puntuar con un signo de exclamación. Hace una ejecución final, más o menos, alrededor de Bash histexpand y toma solo un poco más de tiempo para codificar.

El hexadecimal para un signo de exclamación, como se enumera en http://www.ascii-code.com/ , es 21, por lo que si coloca \x21al final de su cadena echo -e $foo, haga $foosu propio eco expandido [es decir, foo=$(echo -e "$foo")] lo que obtener cuando de echo $foonuevo es la cadena con un !al final. Y tampoco cambiar de histexpand.

Funciona seguro en Bash 4+. Versiones anteriores, ymmv.

Mangas plateadasX
fuente
Hmmm no me funciona.
lzap
No entiendo lo que estás diciendo acerca de hacerse eco. 'echo -e' e 'printf' interpretan los códigos octal, hexadecimal y Unicode escapados. En los casos en que use cualquiera de esos, puede usar "\ 041" (el octal para el "!") O "\ x21" (el hexadecimal) para sustituir el signo de exclamación. Por ejemplo: printf "OMG\041". Si está creando una cadena entre comillas dobles en algún lugar que no sea echo o printf, como la cadena de confirmación sobre la que se le preguntó a OP, puede incrustar $(echo -e "\041")en la cadena donde debería estar el signo de exclamación. De esta manera: bzr commit -m "This is a great commit$(echo -e "\041")".
Todd Walton