Sei que isso !
tem um significado especial na linha de comando no contexto do histórico da linha de comando, mas fora isso, em um script em execução, o ponto de exclamação às vezes pode causar um erro de análise.
Eu acho que tem algo a ver com um event
, mas não tenho idéia do que é um evento ou do que ele faz. Mesmo assim, o mesmo comando pode se comportar de maneira diferente em situações diferentes.
O último exemplo, abaixo, causa um erro; mas por que quando o mesmo código funcionou fora da substituição de comando? .. usando GNU bash 4.1.5
# This works, with or without a space between ! and p
{ echo -e "foo\nbar" | sed -nre '/foo/! p'
echo -e "foo\nbar" | sed -nre '/foo/!p'; }
# bar
# bar
# This works, works when there is a space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/! p')"; echo "$var"
# bar
# This causes an ERROR, with NO space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/!p')"; echo "$var"
# bash: !p': event not found
bash
command-history
quoting
Peter.O
fonte
fonte
protected
teria sido mais apropriado. (protegido por 'aspas simples')var=$(…)
(sem aspas duplas) e funcionará como (eu acho) que você espera. Este é ainda “seguro” porque a parte do valor de uma atribuição simples não está sujeito à repartição de palavras ou englobamento (embora isso não pode ser verdade de atribuições feitas através builtins (por exemploexport
,local
, etc.) em todas as conchas). Infelizmente, isso não se estende para além de atribuições simples, pois as aspas duplas são a maneira de se proteger contra a divisão de palavras e globbing, enquanto ainda se obtém outros tipos de expansão em outros contextos.Respostas:
O
!
personagem invoca a substituição do histórico do bash. Quando seguido por uma sequência (como no exemplo que falhou), ele tenta expandir para o último evento do histórico iniciado com essa sequência. Assim como$var
é expandido para o valor dessa string,!echo
seria expandido para o último comando de eco em seu histórico.O espaço é um personagem de ruptura em tais expansões. Primeira nota como isso funcionaria com variáveis:
O mesmo acontecerá com a expansão da história. O caractere de estrondo (
!
) inicia uma sequência de substituição do histórico, mas apenas se for seguido por uma sequência. Seguindo-o com um espaço, torne-o literal bang, em vez de parte de uma sequência de substituição.Você pode evitar esse tipo de substituição para expansão de variável e histórico usando aspas simples. Seus primeiros exemplos usavam aspas simples e, portanto, funcionavam bem. Seus últimos exemplos estão entre aspas duplas e, portanto, o bash os examinou em busca de sequências de expansão antes de fazer qualquer outra coisa. A única razão pela qual o primeiro não tropeçou é que o espaço é um caractere de interrupção, como mostrado acima.
fonte
var=word; echo "test '$var'"; echo 'test "$var"'
Como já foi dito por Caleb ,
!
é usado para invocar a substituição do histórico do bash.Se, como eu, achar que não precisa desse recurso, desative-o inserindo a seguinte linha
~/.bashrc
:Não preciso disso porque o histórico pode ser recuperado pela seta para cima e Ctrl- rpesquisa reversa incremental. Consulte a página de manual do bash, seção Comandos para manipular o histórico para obter uma lista detalhada de atalhos.
fonte
!!
?set +H
no script funciona tão bem :) +1seu primeiro exemplo:
pode ser reduzido para
Dentro de aspas simples, todos os caracteres preservam seus valores literais. Assim
!
, perdeu seu significado especial e a expansão da história não é pré-formada.seu segundo e terceiro exemplos:
pode ser reduzido para
'! p'
e'!p'
são essencialmente partes das cadeias de caracteres duplas.Dentro de aspas duplas, todos os caracteres preservar seus valores literais , exceto
$
,`
,\
e!
.Isso implica aspas simples
'! p'
e'!p'
perdeu seus significados especiais (isto é, incapaz de escapar!
), mas!
ainda mantém seu significado especial, portanto, a expansão da história é realizada.No entanto, quando
!
é seguido por um caractere de espaço, a expansão do histórico não é executada.Citação de
man bash
:fonte