En bash, comment puis-je échapper à un point d'exclamation?

183

Je veux faire quelque chose comme bzr commit -m "It works!". Je peux en quelque sorte échapper au point d'exclamation en le faisant bzr commit -m "It works\!". Cependant, mon message de validation inclut la barre oblique inversée. Comment puis-je échapper au point d'exclamation tout en ignorant la barre oblique inverse?

Matthieu
la source
1
Faire des bzr commit -m "It works"!travaux, aussi.
kba
1
Comme je l'ai noté précédemment, la commande que vous mettez fonctionne réellement sur elle-même :)bzr commit -m "It works!"
h4unt3r
Un cas encore plus étrange avec des citations imbriquées: stackoverflow.com/questions/22125658/…
Ciro Santilli a écrit:
1
Bien que la réponse acceptée constitue une bonne solution de contournement pour vos problèmes de validation, j’estime que ce n’est pas une réponse au problème actuel: le développement de l’historique de Bash . S'il vous plaît envisager d'accepter la réponse de Dennis?
Arjan

Réponses:

153

Puisque vous ne comptez pas sur bash pour développer les variables dans votre message de validation, vous pouvez utiliser des guillemets simples. Les chaînes entre guillemets simples ne sont pas développées par bash.

bzr commit -m 'This does work!' 
Benjamin Bannier
la source
24
Depuis la question était "Comment puis-je échapper à un point d'exclamation?" et non "Comment ne pas développer un point d'exclamation?" Je ne pense pas que cela soit valide. Il arrive parfois (par exemple, lors du passage d'apostrophes et de points d'exclamation dans la même ligne de commande) que cela ne fonctionne pas. La réponse ci-dessous fonctionne beaucoup mieux pour faire ce dont beaucoup de gens ont besoin.
Jann
7
@Jann: Vous avez tout à fait raison, mais je pense que le problème est celui avec tant de questions sur le superutilisateur: est-ce que nous répondons à la question de manière pertinente ou aidons-nous les gens à résoudre leur problème spécifique? Je pense que les deux manières peuvent être utiles, et cela cherchait de l'aide sur un problème spécifique.
Benjamin Bannier
touché! C'était un problème spécifique. J'ai juste tendance à vouloir une réponse à mes questions pour pouvoir être utilisé dans de nombreuses situations. pS: La raison pour laquelle j'ai même mentionné cela était que j'avais besoin de passer à la fois une apostrophe et un point d'exclamation à un programme Perl et j'avais besoin de la solution ci-dessous. :)
Jann
Je suis d’accord avec Benjamin et Jann mais j’ai donné un vote négatif. Le titre de la question est indexé par les moteurs de recherche et c'est comme ça que je suis arrivé ici et que la plupart des utilisateurs viennent probablement ici. C'est pourquoi j'estime qu'il est important que la question actuelle reflète le problème qui se cache derrière. Dans d'autres forums, il est conseillé (presque obligé) de demander précisément ce qu'ils recherchent. Le fait de répondre à des questions mal exprimées favorise la négligence et c’est la raison exacte de mon vote négatif ici. En guise de compromis / solution, ma suggestion est d’aider à adapter le titre afin qu’il reflète le problème.
ChristophK
153

Voici une autre méthode si vous voulez des guillemets doubles ainsi que l'exclamation:

echo "It's broken"'!'

Cela fonctionne même si le !n'est pas au bout de la ligne.

Par exemple:

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

Bonus: Une technique similaire peut être utilisée pour échapper à tout texte en Sh ou Bash (avec l'aide de sed): voir la première option de cette réponse . De plus, si vous avez bash-completioninstallé, vous avez probablement déjà la quote()fonction disponible.

jwd
la source
4
Bon conseil, JWD. Je n'avais pas réalisé que les chaînes bash pouvaient être concaténées simplement en omettant les espaces entre elles.
Alan H.
En fait, si le point d'exclamation se trouve à la fin de la chaîne, vous êtes en clair, echo "Happy birthday!"cela fonctionnera comme prévu, sinon vous pourrez l'échapper avec une barre oblique inversée, mais la barre oblique inverse sera également imprimée. XD Bash n'est pas pour les âmes sensibles :)
h4unt3r
@ h4unt3r: étrange, ce n'est pas mon expérience. Pour moi, les echo "Happy Birthday!"sorties 2 lignes. Le premier est echo "Happy birthday"(pas d'exclamation) et le second est "Joyeux anniversaire" (encore une fois, pas d'exclamation). Avez-vous activé le développement de l'historique lorsque vous effectuez ce test?
Jwd
@jwd quelle version de bash utilisez-vous? J'ai toujours l'expansion de l'histoire sur. Avez-vous utilisé accidentellement deux !! pour ton test?
h4unt3r
@ h4unt3r:, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)certainement qu'un seul !est utilisé. J'ai histexpandprésent dans $SHELLOPTS. Cependant, je viens d'essayer la version 4.3.18 (2) sur une autre machine et elle se comporte comme vous l'avez décrit. Je suppose que c'est un bug qui a été corrigé.
Jwd
66

Désactiver l' expansion de l'historique :

set +H

ou

set +o histexpand

Vous pouvez ajouter l'une de ces commandes à votre ~/.bashrcsi vous n'utilisez généralement pas l'expansion de l'historique.

Bash 4.3 a ajouté un cas particulier :

le caractère d'expansion de l'historique est également considéré comme cité s'il précède immédiatement la double guillemet fermante dans une chaîne entre guillemets

Dennis Williamson
la source
Merci - cela a fonctionné, mais je devais le faire set +o histexpand, pas set -o histexpand. Pourriez-vous modifier votre réponse pour résoudre ce problème?
Matthew
Oups, faute de frappe, désolé. Fixé.
Dennis Williamson
excellent! cherchais cela pour les âges .... thx vm! comme évasion ne fonctionnera pas ... Je ne veux pas utiliser des guillemets simples aussi ... Je vais ajouter cela à mon .bashrcmerci !!, jamais utilisé !dans les scripts et pour rien !! c'était toujours inquiétant ...
Aquarius Power
C'est vraiment génial! echo "@AquariusPower!"
joehanna
12

Utilisez des guillemets simples (') au lieu de guillemets doubles ("). Les guillemets simples désactivent toute interprétation des éléments qu’ils contiennent, alors que les guillemets n'en désactivent que certaines.

bzr commit -m 'It works!'
KeithB
la source
4

Je viens tout juste de trouver un autre moyen, qui fonctionnera au moins avec echoles chaînes (phrases) que vous voulez ponctuer avec un point d’exclamation. Il effectue plus ou moins une analyse finale de Bash histexpand et ne prend qu'un peu plus de temps à coder.

L'hexagone pour un point d'exclamation, comme indiqué sur http://www.ascii-code.com/ , est 21, donc si vous mettez \x21à la fin de votre chaîne, echo -e $foo, faire $fooson propre écho élargi [c. -à- foo=$(echo -e "$foo")], ce que vous obtenez quand vous echo $fooest à nouveau la chaîne avec un !à la fin. Et pas de commutation histexpand non plus.

Fonctionne à coup sûr dans Bash 4+. Les versions précédentes, ymmv.

SilversleevesX
la source
Hmmm ça ne marche pas pour moi.
Lzap
Je ne comprends pas ce que vous dites à propos de se faire écho. 'echo -e' et 'printf' interprètent les codes octaux, hexadécimaux et Unicode échappés. Dans les cas où vous utilisez l'une de ces options, vous pouvez utiliser "\ 041" (l'octal pour "!") Ou "\ x21" (l'hex) pour remplacer le point d'exclamation. Par exemple: printf "OMG\041". Si vous construisez une chaîne entre guillemets qui ne soit ni echo ni printf, comme la chaîne de validation à laquelle on vous a demandé de parler, vous pouvez l'intégrer $(echo -e "\041")à l'emplacement où devrait se trouver le point d'exclamation. Comme ceci: bzr commit -m "This is a great commit$(echo -e "\041")".
Todd Walton le