Bash set + x sans qu'il soit imprimé


92

Est-ce que quelqu'un sait si nous pouvons dire set +xen bash sans qu'il soit imprimé:

set -x
command
set +x

traces

+ command
+ set +x

mais il devrait juste imprimer

+ command

Bash est la version 4.1.10 (4). Cela me dérange depuis un certain temps maintenant - la sortie est encombrée de set +xlignes inutiles , ce qui rend la fonction de trace pas aussi utile qu'elle pourrait l'être.


Cela ne répond pas à votre question, mais lorsque vous exécutez votre script, pourquoi pas:script.sh 2>&1 | grep -v 'set +x'
cdarke

Réponses:


145

J'ai eu le même problème, et j'ai pu trouver une solution qui n'utilise pas de sous-shell:

set -x
command
{ set +x; } 2>/dev/null

10
Excellente réponse, juste une note: sans point-virgule après la commande, cela ne fonctionnera pas; et avec un point-virgule mais sans espaces entre accolades, une erreur de syntaxe sera générée.
sdaau

9
Cela remet à zéro l'état de sortie.
Garth Kidd

8
Le statut de sortie @GarthKidd est remis à zéro à chaque commande réussie. set +xest une telle commande réussie
Daniel Alder

3
Dans les cas où vous avez besoin de l'état de sortie command, cette variation est une solution: { STATUS=$?; set +x; } 2>/dev/null. Ensuite, inspectez $STATUSles lignes suivantes à votre guise.
Greg Price

5
Par ailleurs, voici une version golfed un peu plus loin: { set +x; } 2>&-. Cela ferme purement et simplement fd 2 plutôt que de le faire pointer sur / dev / null. Certains programmes ne gèrent pas très bien lorsqu'ils essaient d'imprimer sur stderr, c'est pourquoi / dev / null est un bon style en général; mais le set -xtraçage du shell le gère très bien, donc cela fonctionne parfaitement ici, et cela rend cette incantation un peu plus courte.
Greg Price

43

Vous pouvez utiliser un sous-shell. À la sortie du sous-shell, le paramètre à xsera perdu:

( set -x ; command )

Eh bien, merci ... bon point. En fait, je suis au courant de «l'astuce du sous-shell». J'espérais que ça pourrait être plus facile que ça. Cela implique des changements substantiels dans le code, rendant le code plus complexe et moins lisible. IMHO ce serait pire que de vivre avec l'ensemble + x lignes ...
Andreas Spindler

Je ne vois pas comment ( set -x \n command \n )est pire set -x \n command \n set +x.
chepner

3
@chepner: vous ne pouvez pas définir de variables.
choroba

2
... et vous ne pouvez pas cd: cela ne change pas le répertoire courant dans le shell parent.
Andreas Spindler

Désolé, je ne suis pas sûr de ce que je pensais être votre objection. Ça a été une longue semaine ...
chepner

8

J'ai piraté une solution à cela tout récemment quand je suis devenu ennuyé avec cela:

shopt -s expand_aliases
_xtrace() {
    case $1 in
        on) set -x ;;
        off) set +x ;;
    esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'

Cela vous permet d'activer et de désactiver xtrace comme dans l'exemple suivant, où je consigne comment les arguments sont affectés aux variables:

xtrace on
ARG1=$1
ARG2=$2
xtrace off

Et vous obtenez une sortie qui ressemble à:

$ ./script.sh one two
+ ARG1=one
+ ARG2=two

Astuce intelligente (même si vous n'avez pas besoin de la /dev/stdinpièce). La mise en garde est que l'activation de l'extension d'alias dans les scripts peut avoir des effets secondaires indésirables.
mklement0

Vous avez raison. J'ai modifié la réponse pour supprimer le superflu /dev/stdin. Je n'ai connaissance d'aucun effet secondaire spécifique, car l'environnement non interactif ne devrait charger aucun fichier définissant des alias. Quels effets secondaires pourrait-il y avoir?
user108471

1
C'est un bon point - j'ai oublié que les alias ne sont pas hérités, donc le risque est beaucoup plus petit que je ne le pensais (hypothétiquement, votre script pourrait s'approvisionner en code tiers qui définit les alias, mais je suis d'accord que ce n'est probablement pas un réel- préoccupation mondiale). +1
mklement0

1
@AndreasSpindler Pourriez-vous expliquer pourquoi vous pensez que cette technique est plus susceptible de divulguer des informations plus sensibles?
user108471

1
... essentiellement parce que les alias et les fonctions sont des constructions de haut niveau. set +xest beaucoup plus difficile (sinon impossible) de faire des compromis. Mais c'est toujours une bonne et simple solution - probablement la meilleure à ce jour.
Andreas Spindler

7

Que diriez-vous d'une solution basée sur une version simplifiée de @ user108471:

shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'

trace_on
...stuff...
trace_off

Que dis-tu de ça? function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH

1

C'est une combinaison de quelques idées qui peuvent entourer un bloc de code et préserver l'état de sortie.

#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'

trace_on
echo hello
trace_off
echo "status: $?"

trace_on
(exit 56)
trace_off

Une fois exécuté:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56


Bel effort mais je pense que le ()tour exitn'est pas nécessaire. D'accord. Peut-être que paranoïaque, mais si ce code est utilisé en général vous avez un bon vecteur d'attaque: Redéfinir trace_onet trace_offet le code inject qui lit les commandes exécutées. Si vous utilisez de telles "utilités" seules, c'est instructif, mais si le code est utilisé avec d'autres, vous devez vous demander si les avantages de ces fonctions non standardisées l'emportent sur les inconvénients. Personnellement, je me suis installé { set +x; } 2>/dev/nullcar cette construction est généralement comprise et ne change pas non plus le statut de sortie.
Andreas Spindler
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.