Como ecoar um estrondo!

53

Eu tentei criar um script por echo 'inserindo o conteúdo em um arquivo, em vez de abri-lo com um editor

echo -e "#!/bin/bash \n /usr/bin/command args"  > .scripts/command

A saída :

bash: !/bin/bash: event not found

Eu isolei esse comportamento estranho para o estrondo .

$ echo !
!  

$ echo "!"
bash: !: event not found

$ echo \#!
#!

$ echo \#!/bin/bash
bash: !/bin/bash: event not found
  • Por que o bang está causando isso?
  • Quais são esses "eventos" aos quais o bash se refere?
  • Como posso superar esse problema e imprimir "#! / bin / bash" na tela ou no arquivo?
por Stefan 13.10.2010 / 10:44

6 respostas

53

Tente usar aspas simples.

echo -e '#!/bin/bash \n /usr/bin/command args'  > .scripts/command

echo '#!'

echo '#!/bin/bash'

O problema está ocorrendo porque o bash está pesquisando seu histórico para! / bin / bash. Usar aspas simples escapa desse comportamento.

    
por 13.10.2010 / 11:17
16

Como Richm disse , o bash está tentando fazer uma correspondência histórica . Outra maneira de evitar isso é simplesmente escapar do estrondo com um \ :

$ echo \#\!/bin/bash
#!/bin/bash

Embora tenha em atenção que dentro de aspas duplas, o \ não é removido:

$ echo "\!"
\!
    
por 13.10.2010 / 15:58
13

! inicia uma substituição de histórico (um “evento” é uma linha no histórico de comandos); por exemplo, !ls expande para o último comando que começa com ls e !?foo expande para o último comando que contém foo . Você também pode extrair palavras específicas (por exemplo, !!:1 refere-se à primeira palavra do comando anterior) e mais; veja o manual para detalhes.

Esse recurso foi inventado para recuperar rapidamente os comandos anteriores nos dias em que a edição da linha de comando era primitiva. Com shells modernos (pelo menos bash e zsh) e copy-and-paste, a expansão da história não é tão útil quanto costumava ser - ainda é útil, mas você pode passar sem isso.

Você pode alterar qual caractere aciona a substituição do histórico configurando a variável histchars ; Se você raramente usa a substituição do histórico, pode definir, por exemplo histchars='¡^' , de modo que ¡ inicie a expansão do histórico em vez de ! . Você pode até mesmo desativar o recurso com set +o histexpand .

    
por 13.10.2010 / 20:33
3

Para poder desativar a expansão do histórico em uma linha de comando específica, você pode usar space como o terceiro caractere de $histchars :

histchars='!^ '

Em seguida, se você digitar seu comando com um espaço à esquerda, a expansão do histórico não será executada.

bash-4.3$ echo "#!/bin/bash"
bash: !/bin/bash: event not found
bash-4.3$  echo "#!/bin/bash"
#!/bin/bash

No entanto, observe que os espaços iniciais também são usados quando $HISTCONTROL contém ignorespace como uma maneira de informar bash para não gravar uma linha de comando no histórico.

Se você quiser os dois recursos de maneira indecorosa, precisará escolher outro caractere como o terceiro caractere de $histchars . Você quer um que não afete a maneira como seu comando é interpretado. Algumas opções:

  • usando barra invertida ( \ ): \echo foo funciona, mas isso tem o efeito colateral de desativar aliases ou palavras-chave.
  • TAB: para inseri-lo na primeira posição, você precisa pressionar Ctrl + V Tab .
  • Se você não se importar em digitar duas teclas, poderá escolher qualquer caractere que normalmente não apareça na primeira posição ( % , @ , ? , escolha a sua) e criar um alias vazio para isso:

    histchars='!^%'
    alias %=
    

    Em seguida, insira esse caractere, espaço e seu comando:

    bash-4.3$ % echo !!
    !!
    

(você não poderá gravar um comando no qual a substituição do histórico foi desativada. Observe também que o terceiro caractere padrão de $histchars é # para que a expansão do histórico não seja feita nos comentários. mudá-lo, e você inserir comentários no prompt, você deve estar ciente do fato de que! seqüências podem ser expandidas lá).

    
por 21.08.2014 / 23:17
2

As soluções propostas não funcionam, por exemplo, no exemplo a seguir:

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

Nesse caso, o estrondo pode ser impresso usando seu código octal ASCII:

$ bash -c "echo -e 'hello World
$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$
41'" hello World! $
    
por 24.12.2010 / 18:40
-1

Desde o Bash 4.3, agora você pode usar aspas duplas para citar o caractere de expansão do histórico:

$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!
    
por 16.09.2016 / 14:18