it-swarm-pt.com

Como ecoar um estrondo!

Tentei criar um script 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: evento não encontrado

Eu isolei esse comportamento estranho ao bang .

$ 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 superar esse problema e imprimir "#!/Bin/bash" na tela ou no meu arquivo?
59
Stefan

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 em seu histórico!/Bin/bash. O uso de aspas simples evita esse comportamento.

62
Richm

Como Richm disse , o bash está tentando fazer um correspondência de histórico . Outra maneira de evitá-lo é simplesmente escapar do estrondo com um \:

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

Embora tenha cuidado com o aspas duplas, o \ não é removido:

$ echo "\!"
\!
18
Michael Mrozek

! inicia uma substituição do histórico (um "evento" é uma linha no histórico de comandos); por exemplo !ls expande para a última linha de comando que contém ls e !?foo expande para a última linha de 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 comandos anteriores nos dias em que a edição da linha de comandos era primitiva. Com shells modernos (pelo menos bash e zsh) e copiar e colar, a expansão do histórico não é tão útil quanto costumava ser - ainda é útil, mas você pode sobreviver sem ele.

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

14

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='!^ '

Então, 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

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

Se você deseja que os dois recursos sejam independentes, 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 tem o efeito colateral de desativar aliases ou palavras-chave.
  • TAB: para inseri-lo na primeira posição, você precisa pressionar Ctrl+VTab Apesar.
  • se você não se importa em digitar duas teclas, pode escolher qualquer caractere que normalmente não aparece na primeira posição (%, @, ?, escolha o seu) e crie um alias vazio para ele:

    histchars='!^%'
    alias %=
    

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

    bash-4.3$ % echo !!
    !!
    

(você não poderá gravar um comando em que 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. Se você o alterar e inserir comentários no Prompt, esteja ciente do fato de que! seqüências podem ser expandidas para lá).

4
Stéphane Chazelas

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\0041'"
hello World!
$
2
Atti

Uma solução simples ainda não mencionada é usar uma variável:

$ var='!'
$ echo -e "#${var}/bin/bash \n /usr/bin/command args"  > .scripts/command

Imprimindo um bang! é não um problema quando a string não está entre aspas ou está entre aspas simples ou dentro de uma C-String

$ echo hi\!pal 'hi!pal' $'hi!pal'
hi!pal 'hi!pal' $'hi!pal'

Também não é um problema quando o histexpand está desabilitado (shopt -ou histexpand ou set +o histexpand ou simplesmente set +H. Também é possível alterar os caracteres de expansão e facilitar a impressão de um bang!.

Mas a solução mais simples portátil é: use um var

$ var='!'
$ echo "hi${var}pal"
hi!pal
0
Isaac