Je me rends compte que cela !
a une signification particulière sur la ligne de commande dans le contexte de l'historique de la ligne de commande, mais à part cela, dans un script d'exécution, le point d'exclamation peut parfois provoquer une erreur d'analyse.
Je pense que cela a quelque chose à voir avec un event
, mais je n'ai aucune idée de ce qu'est un événement ou de ce qu'il fait. Même ainsi, la même commande peut se comporter différemment dans différentes situations.
Le dernier exemple, ci-dessous, provoque une erreur; mais pourquoi, quand le même code a fonctionné en dehors de la substitution de commande? .. en utilisant 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
la source
la source
protected
aurait été plus approprié. (protégé par des `` guillemets simples '')var=$(…)
(pas de guillemets doubles), et cela fonctionnera comme (je pense) que vous attendez. Ceci est encore « sûr » parce que la partie de la valeur d'une affectation simple n'est pas soumise à la séparation de mots ou englobement (bien que cela ne peut être vrai des missions effectuées par builtins (par exempleexport
,local
etc.) sous toutes les coquilles). Malheureusement, cela ne va pas au-delà des affectations simples, car les guillemets doubles sont le moyen de se protéger contre le fractionnement et la globalisation des mots tout en obtenant d'autres types d'expansion dans d'autres contextes.Réponses:
Le
!
personnage invoque la substitution d'historique de bash. Lorsqu'il est suivi d'une chaîne (comme dans votre exemple défaillant), il essaie de se développer jusqu'au dernier événement d'historique qui a commencé avec cette chaîne. Tout comme$var
est étendu à la valeur de cette chaîne,!echo
s'étendrait à la dernière commande echo de votre historique.L'espace est un personnage de rupture dans de telles extensions. Notez d'abord comment cela fonctionnerait avec des variables:
La même chose se produira pour l'expansion de l'histoire. Le caractère bang (
!
) démarre une séquence de remplacement d'historique, mais uniquement s'il est suivi d'une chaîne. Le suivre avec un espace en fait un coup littéral au lieu d'une partie d'une séquence de remplacement.Vous pouvez éviter ce type de remplacement à la fois pour les expansions de variables et d'historique en utilisant des guillemets simples. Vos premiers exemples ont utilisé des guillemets simples et se sont donc bien déroulés. Vos derniers exemples sont entre guillemets et bash les a donc scannés pour les séquences d'expantion avant qu'il ne fasse autre chose. La seule raison pour laquelle le premier ne s'est pas déclenché est que l'espace est un caractère de pause comme indiqué ci-dessus.
la source
var=word; echo "test '$var'"; echo 'test "$var"'
Comme déjà dit par Caleb ,
!
est utilisé pour invoquer la substitution d'historique de bash.Si comme moi vous sentez que vous n'avez pas besoin d'une telle fonctionnalité, vous pouvez la désactiver en insérant la ligne suivante
~/.bashrc
:Je ne ai pas besoin parce que l'histoire peut être récupéré par la flèche haut et Ctrl- rrecherche inversée incrémentale. Voir la page de manuel de bash, section Commandes de manipulation de l'historique pour une liste détaillée des raccourcis.
la source
!!
?set +H
dans le script fonctionne tout aussi bien :) +1votre premier exemple:
pourrait être réduit à
Dans les guillemets simples, tous les caractères conservent leurs valeurs littérales. Ainsi
!
a perdu son sens particulier et l'expansion de l'histoire n'est pas préformée.vos deuxième et troisième exemples:
pourrait être réduit à
'! p'
et'!p'
font essentiellement partie des chaînes entre guillemets doubles.Entre guillemets, tous les caractères conservent leurs valeurs littérales , à l' exception
$
,`
,\
et!
.Cela implique les guillemets simples de
'! p'
et'!p'
ont perdu leur signification spéciale (c'est-à-dire: incapable de s'échapper!
) mais!
conserve toujours sa signification spéciale, ainsi une expansion de l'histoire est effectuée.Cependant, lorsqu'il
!
est suivi d'un caractère espace, l'expansion de l'historique n'est pas effectuée.Citant de
man bash
:la source