O caractere !
invoca a substituição do histórico do bash. Quando seguido por uma string (como em seu exemplo com falha), ele tenta expandir para o último evento de histórico que começou com essa string. 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 que quebra em tais expansões. Primeiro, observe como isso funcionaria com as variáveis:
# var="like"
# echo "$var"
like
# echo "$"
$
# echo "Do you $var frogs?"
Do you like frogs? <- as expected, variable name broken at space
# echo "Do you $varfrogs?"
Do you? <- $varfrogs not defined, replaced with blank
# echo "Do you $ var frogs?"
Do you $ var frogs? <- $ not a valid variable name, ignored
A mesma coisa acontecerá para a expansão da história. O caractere bang ( !
) inicia uma sequência de substituição de histórico, mas apenas se for seguido por uma string. Segui-lo com um espaço faz com que seja literal bang em vez de parte de uma sequência de substituição.
Você pode evitar esse tipo de substituição para variáveis e para a execução de histórico usando aspas simples. Seus primeiros exemplos usavam aspas simples e, portanto, funcionavam bem. Seus últimos exemplos estão entre aspas duplas e, assim, bash os escaneou para seqüências de expansão antes de fazer qualquer outra coisa. A única razão pela qual o primeiro não desarmou é que o espaço é um caractere de quebra, como mostrado acima.