Lorsque vous êtes à la hauteur de votre cou en alligators, il est facile d'oublier que le but était de drainer le marais.
- dicton populaire
La question porte sur echo
, et pourtant la majorité des réponses jusqu'à présent se sont concentrées sur la façon d'introduire une set +x
commande. Il existe une solution beaucoup plus simple et plus directe:
{ echo "Message"; } 2> /dev/null
(Je reconnais que je n'aurais peut-être pas pensé au { …; } 2> /dev/null
si je ne l'avais pas vu dans les réponses précédentes.)
C'est un peu lourd, mais si vous avez un bloc de echo
commandes consécutives , vous n'avez pas besoin de le faire sur chacune d'elles individuellement:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Notez que vous n'avez pas besoin de points-virgules lorsque vous avez des retours à la ligne.
Vous pouvez réduire la charge de frappe en utilisant l'idée
de kenorb d'ouvrir en /dev/null
permanence sur un descripteur de fichier non standard (par exemple, 3), puis en disant 2>&3
au lieu de 2> /dev/null
tout le temps.
Les quatre premières réponses au moment d'écrire ces lignes nécessitent de faire quelque chose de spécial (et, dans la plupart des cas, lourd) à
chaque fois que vous faites un echo
. Si vous voulez vraiment que toutes les echo
commandes suppriment la trace d'exécution (et pourquoi pas?), Vous pouvez le faire globalement, sans munging beaucoup de code. Tout d'abord, j'ai remarqué que les alias ne sont pas tracés:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Notez que les extraits de script suivants fonctionnent si le shebang est #!/bin/sh
, même s'il /bin/sh
s'agit d'un lien vers bash. Mais, si le shebang l'est #!/bin/bash
, vous devez ajouter une shopt -s expand_aliases
commande pour que les alias fonctionnent dans un script.)
Donc, pour mon premier tour:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Maintenant, quand nous disons echo "Message"
, nous appelons l'alias, qui n'est pas tracé. L'alias désactive l'option de trace, tout en supprimant le message de trace de la set
commande (en utilisant la technique présentée en premier dans la réponse de user5071535 ), puis exécute la echo
commande réelle . Cela nous permet d'obtenir un effet similaire à celui de la réponse de user5071535 sans avoir à modifier le code à chaque echo
commande. Cependant, cela laisse le mode trace désactivé. Nous ne pouvons pas mettre un set -x
dans l'alias (ou du moins pas facilement) car un alias permet uniquement de substituer une chaîne à un mot; aucune partie de la chaîne d'alias ne peut être injectée dans la commande
après les arguments (par exemple, "Message"
). Ainsi, par exemple, si le script contient
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
la sortie serait
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
vous devez donc réactiver l'option trace après avoir affiché le (s) message (s) - mais seulement une fois après chaque bloc de echo
commandes consécutives :
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Ce serait bien si nous pouvions faire l' set -x
automatique après un echo
- et nous pouvons, avec un peu plus de ruse. Mais avant de présenter cela, réfléchissez à cela. L'OP commence avec des scripts qui utilisent un #!/bin/sh -ex
shebang. Implicitement, l'utilisateur pourrait supprimer le x
du shebang et avoir un script qui fonctionne normalement, sans traçage d'exécution. Ce serait bien si nous pouvions développer une solution qui conserve cette propriété. Les premières réponses ici échouent à cette propriété car elles réactivent le traçage des echo
déclarations après , sans condition, sans se soucier de savoir si c'était déjà le cas.
Cette réponse ne reconnaît visiblement pas ce problème, car elle remplace echo
sortie avec sortie trace; par conséquent, tous les messages disparaissent si le suivi est désactivé. Je vais maintenant présenter une solution qui réactivera le traçage après une echo
déclaration conditionnellement - uniquement si elle était déjà activée. La rétrogradation à une solution qui active le «retour» du traçage sans condition est triviale et est laissée comme exercice.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
est la liste des options; une concaténation des lettres correspondant à toutes les options définies. Par exemple, si les options e
et x
sont définies, alors $-
sera un mélange de lettres qui comprend e
et x
. Mon nouvel alias (ci-dessus) enregistre la valeur de $-
avant de désactiver le traçage. Ensuite, avec le suivi désactivé, il jette le contrôle sur une fonction shell. Cette fonction fait le réel echo
et vérifie ensuite si l' x
option a été activée lorsque l'alias a été appelé. Si l'option était activée, la fonction la rallume; s'il était désactivé, la fonction le laisse désactivé.
Vous pouvez insérer les sept lignes ci-dessus (huit, si vous incluez un shopt
) au début du script et laisser le reste tranquille.
Cela vous permettrait
- d'utiliser l'une des lignes de shebang suivantes:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
ou tout simplement#! / bin / sh
et cela devrait fonctionner comme prévu.
- avoir du code comme
(shebang)
commande 1
commande 2
commande 3
set -x
commande 4
commande 5
commande 6
set + x
commande 7
commande 8
commande 9
et
- Les commandes 4, 5 et 6 seront tracées - sauf si l'une d'elles est un
echo
, auquel cas elle sera exécutée mais pas tracée. (Mais même si la commande 5 est un echo
, la commande 6 sera toujours tracée.)
- Les commandes 7, 8 et 9 ne seront pas tracées. Même si la commande 8 est un
echo
, la commande 9 ne sera toujours pas tracée.
- Les commandes 1, 2 et 3 seront tracées (comme 4, 5 et 6) ou non (comme 7, 8 et 9) selon que le shebang inclut
x
.
PS J'ai découvert que, sur mon système, je peux laisser de côté le builtin
mot - clé dans ma réponse du milieu (celui qui est juste un alias echo
). Ce n'est pas surprenant; bash (1) dit que, pendant l'expansion des alias,…
… Un mot identique à un alias en cours de développement n'est pas développé une deuxième fois. Cela signifie que l' on peut alias ls
pour ls -F
, par exemple, et bash ne cherche pas à développer récursive le texte de remplacement.
Sans surprise, la dernière réponse (celle avec echo_and_restore
) échoue si le builtin
mot-clé est omis 1 . Mais, curieusement, cela fonctionne si je supprime le builtin
et change la commande:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Il semble donner lieu à un comportement indéfini. j'ai vu
- une boucle infinie (probablement à cause d'une récursion illimitée),
- un
/dev/null: Bad address
message d'erreur, et
- un core dump.
echo +x; echo "$*"; echo -x
un alias, j'aimerais le voir.