bash: échapper les lignes individuelles de l'écho `-x`

11

En bash, lors de l'exécution avec l' -xoption, est-il possible d'exempter les commandes individuelles de l'écho?

J'essaie de rendre la sortie aussi nette que possible, donc j'exécute certaines parties de mon script en sous-shell avec set +x. Cependant, la ligne set +xelle-même est toujours en écho et n'ajoute aucune information précieuse à la sortie.

Je me souviens du mauvais vieux .battemps, lors de l'exécution avec echo on, les lignes individuelles pouvaient être exemptées en les commençant par un @. Y a-t-il un équivalent en bash?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

Lors de l'exécution de ce qui précède, la sortie est:

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on
clacke
la source

Réponses:

22

xtracela sortie va à stderr, vous pouvez donc rediriger stderrvers /dev/null:

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

Si vous voulez toujours voir les erreurs des commandes exécutées dans les fonctions, vous pouvez faire

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

Notez l'utilisation de (...)au lieu de {...}pour fournir une portée locale pour cette fonction via un sous-shell. bash, puisque la version 4.4 prend désormais en charge local -comme dans le shell Almquist pour rendre les options locales à la fonction (similaire à set -o localoptionsin zsh), vous pouvez donc éviter le sous-shell en faisant:

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Une alternative pour bash4.0 à 4.3 serait d'utiliser la $BASH_XTRACEFDvariable et d'avoir un descripteur de fichier dédié ouvert /dev/nullpour cela:

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Puisqu'il bashn'a pas la possibilité de marquer un fd avec le drapeau close-on-exec , cela a pour effet secondaire de divulguer ce fd à d'autres commandes.

Voir aussi ce locvar.sh qui contient quelques fonctions pour implémenter la portée locale des variables et des fonctions dans les scripts POSIX et fournit également des fonctions trace_fnet untrace_fnpour les rendre xtrace d ou non.

Stéphane Chazelas
la source
Sucré! Je cherchais pour voir s'il y avait des modificateurs que je pouvais appliquer à la fonction elle-même, mais je n'ai pas pensé à simplement rediriger stderr. Merci!
clacke
1
Btw, stchaz.free.fr/which_interpreter de la même page est assez génial et dérangeant. :-)
clacke
Et maintenant, je suis revenu ici pour la deuxième méthode, mettre en sourdine set + x sans faire taire la sortie stderr utile. Merci encore!
2013
2

La raison qui set +xest imprimée est que cela set -xsignifie "imprimer la commande que vous êtes sur le point d'exécuter, avec des extensions, avant de l'exécuter . Donc, le shell ne sait pas que vous voulez qu'il n'imprime pas les choses tant qu'il n'a pas imprimé la ligne lui disant de ne pas pour imprimer des choses. À ma connaissance, il n'y a aucun moyen d'empêcher cela de se produire.

Jenny D
la source
0

Voici la solution que vous recherchiez:

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

La commande d'origine s'exécute dans le même shell sous une transformation d'identité. Juste avant l'exécution, vous obtenez une trace non récursive des arguments. Cela vous permet de retracer les commandes qui vous intéressent sans spamer stederr avec des copies en double de chaque commande "echo".

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated
Dave Dopson
la source
Ou à éviter perl(et problèmes avec les commandes multi-lignes):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Stéphane Chazelas
Non, désolé, unix.stackexchange.com/a/60049/17980 est la solution que je cherchais. :-) Les set -xmanœuvres m'achètent-elles quelque chose par rapport à juste printf >&2 '+ %s\n' "$*"?
clacke
Comme dans:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
clacke