No bash, como faço para escapar de um ponto de exclamação?

183

Eu quero fazer algo parecido bzr commit -m "It works!". Eu posso escapar do ponto de exclamação fazendo isso bzr commit -m "It works\!". No entanto, minha mensagem de confirmação inclui a barra invertida. Como escapar do ponto de exclamação, enquanto ainda ignoro a barra invertida?

Mateus
fonte
1
Fazer bzr commit -m "It works"!obras também.
Kba 18/05
1
Como eu disse antes do comando que você colocar realmente funciona por si própria :)bzr commit -m "It works!"
h4unt3r
Um caso ainda mais peculiar com aspas aninhadas: stackoverflow.com/questions/22125658/…
Ciro Santilli escreveu
1
Embora a resposta aceita seja uma boa solução para seus problemas de confirmação, acho que não é uma resposta para o problema real: expansão do histórico do Bash . Por favor, considere aceitar a resposta de Dennis?
Arjan #

Respostas:

153

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

bzr commit -m 'This does work!' 
Benjamin Bannier
fonte
24
Como a pergunta era "Como escapar de um ponto de exclamação?" e não "Como não expiro um ponto de exclamação?" Eu não acho que isso seja válido. Há alguns momentos (como ao passar apóstrofes e pontos de exclamação na mesma linha de comando) que isso não funciona. A resposta abaixo funciona muito melhor para fazer o que muitas pessoas precisam.
Jann
7
@ Jann: Você está 100% certo sobre isso, mas acho que o problema aqui é o de tantas perguntas sobre o superusuário: Nós respondemos a pergunta diretamente ou ajudamos as pessoas a resolver seu problema específico. Acho que os dois lados podem ser úteis, e isso estava procurando ajuda em um problema específico.
Benjamin Bannier
touché! Este foi um problema específico. Eu só tendem a querer uma resposta para minhas perguntas para poder ser usada em muitas situações. pS: O motivo pelo qual mencionei isso foi que eu estava passando um apóstrofo e um ponto de exclamação para um programa perl e precisava da solução abaixo. :)
Jann 24/05
Concordo com Benjamin e Jann, mas dei um voto negativo. O título da pergunta é indexado pelos mecanismos de pesquisa e foi assim que eu vim aqui e provavelmente a maioria dos usuários vem aqui. É por isso que acredito que é importante que a pergunta real reflita o problema por trás dela. Em outros fóruns, as pessoas são aconselhadas (quase forçadas) a perguntar exatamente o que procuram. Responder a perguntas mal expressas apóia a negligência e essa é a razão exata do meu voto negativo aqui. Como compromisso / solução, minha sugestão é ajudar a adaptar o cabeçalho para que ele reflita o problema real.
ChristophK
153

Aqui está outro método, se você quiser aspas duplas, além da exclamação:

echo "It's broken"'!'

Isso funciona mesmo que !não esteja no final da linha.

Por exemplo:

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

Bônus: Uma técnica semelhante pode ser usada para escapar de qualquer texto em Sh ou Bash (com a ajuda de sed): veja a primeira opção nesta resposta . Além disso, se você bash-completioninstalou, provavelmente já possui a quote()função disponível.

jwd
fonte
4
Ótima dica, JWD. Eu não sabia que as seqüências de caracteres bash poderiam ser concatenadas simplesmente omitindo o espaço em branco entre elas.
Alan H.
Na verdade, se o ponto de exclamação estiver no final da string, você estará limpo echo "Happy birthday!", conforme o esperado, caso contrário, poderá escapar com uma barra invertida, mas a barra invertida será impressa também. XD Bash não é para os fracos de coração :)
H4unt3r
@ h4unt3r: Estranho, essa não é a minha experiência. Para mim, echo "Happy Birthday!"gera 2 linhas. O primeiro é echo "Happy birthday"(sem exclamação) e o segundo é "Feliz aniversário" (novamente, sem exclamação). Você tem a expansão do histórico ativada ao fazer este teste?
jwd
@jwd qual versão do bash você está executando? Eu sempre tenho uma expansão histórica. Você acidentalmente usou dois !! para o seu teste?
H4unt3r
@ h4unt3r:, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)definitivamente apenas um !sendo usado. Eu tenho histexpandpresente $SHELLOPTS. No entanto, tentei apenas liberar o 4.3.18 (2) em outra máquina e ele se comporta como você descreveu. Eu acho que foi um bug que foi corrigido.
jwd
66

Desative a expansão do histórico :

set +H

ou

set +o histexpand

Você pode adicionar um desses comandos ao seu ~/.bashrcse você normalmente não usa a expansão do histórico.

O Bash 4.3 adicionou um caso especial :

o caractere de expansão do histórico também é tratado como citado se preceder imediatamente a aspas duplas de fechamento em uma sequência de aspas duplas

Dennis Williamson
fonte
Obrigado - isso funcionou, mas eu tive que fazer set +o histexpand, não set -o histexpand. Você poderia editar sua resposta para corrigir isso?
22710 Matthew
Opa, erro de digitação, desculpe. Fixo.
Dennis Williamson
excelente! estava procurando isso por AGES .... thx vm! como escape não vai funcionar ... Eu não quero usar aspas simples também ... Vou adicionar isso ao meu .bashrcthx !!, nunca usado !em scripts e por nada !! sempre foi preocupante ...
Aquarius Power
Isso é tão incrível! echo "@AquariusPower!"
joehanna
12

Use aspas simples (') em vez de aspas duplas ("). As aspas simples desativam toda a interpretação do conteúdo, enquanto as aspas duplas desativam apenas algumas.

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

Acabei de encontrar outra maneira, que pelo menos funcionará com echoas strings (frases) que você deseja pontuar com um ponto de exclamação. Ele executa uma execução final, mais ou menos, em torno da expansão do Bash e leva apenas um pouco mais de tempo para codificar.

O hexadecimal para um ponto de exclamação, conforme listado em http://www.ascii-code.com/ , é 21; portanto, se você colocar \x21no final da sua string echo -e $foo, faça $fooseu próprio eco expandido [ou seja, foo=$(echo -e "$foo")] get quando você echo $foonovamente é a string com um !no final. E também não é possível mudar de assunto.

Funciona com certeza no Bash 4+. Versões anteriores, ymmv.

SilversleevesX
fonte
Hummm, isso não funciona para mim.
lzap
Eu não entendo o que você está dizendo sobre ecoar em si. 'echo -e' e 'printf' interpretam códigos octal, hex e Unicode de escape. Nos casos em que você estiver usando um desses, você pode usar "\ 041" (o octal para o "!") Ou "\ x21" (o hex) para substituir o ponto de exclamação. Por exemplo: printf "OMG\041". Se você estiver construindo uma cadeia de caracteres com aspas duplas em algum lugar que não seja eco ou printf, como a cadeia de confirmação OP consultada, você poderá incorporar $(echo -e "\041")a cadeia de caracteres onde deveria estar o ponto de exclamação. Como esta: bzr commit -m "This is a great commit$(echo -e "\041")".
Todd Walton