Bash impostato + x senza che venga stampato


92

Qualcuno sa se possiamo dire set +xin bash senza che venga stampato:

set -x
command
set +x

tracce

+ command
+ set +x

ma dovrebbe solo stampare

+ command

Bash è la versione 4.1.10 (4). Questo mi sta infastidendo da un po 'di tempo: l'output è ingombro di set +xlinee inutili , rendendo la funzione di traccia non così utile come potrebbe essere.


Questo non risponde alla tua domanda, ma quando esegui lo script perché no:script.sh 2>&1 | grep -v 'set +x'
cdarke

Risposte:


145

Ho avuto lo stesso problema e sono riuscito a trovare una soluzione che non utilizza una subshell:

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

10
Ottima risposta, solo una nota: senza un punto e virgola dopo il comando non funzionerà; e con un punto e virgola ma senza spazi tra le parentesi graffe, verrà generato un errore di sintassi.
sdaau

9
Questo azzera lo stato di uscita.
Garth Kidd

8
Lo stato di uscita di @GarthKidd viene azzerato ad ogni comando riuscito. set +xè un tale comando di successo
Daniel Alder

3
Nei casi in cui è necessario lo stato di uscita command, questa variazione è una soluzione: { STATUS=$?; set +x; } 2>/dev/null. Quindi ispeziona $STATUSnelle righe successive a tuo piacimento.
Greg Price,

5
Separatamente, ecco una versione un po 'più giocato a golf: { set +x; } 2>&-. Questo chiude completamente fd 2 invece di farlo puntare a / dev / null. Alcuni programmi non gestiscono così bene quando provano a stampare su stderr, motivo per cui / dev / null è un buon stile in generale; ma il set -xtracciamento del guscio lo gestisce bene, quindi funziona perfettamente qui, e rende questo incantesimo un po 'più breve.
Greg Price

43

Puoi usare una subshell. All'uscita dalla subshell, l'impostazione su xandrà persa:

( set -x ; command )

Bene, grazie ... buon punto. In realtà sono consapevole del "trucco del sub-shell". Speravo potesse essere più facile di così. Comporta modifiche sostanziali al codice, rendendolo più complesso e meno leggibile. IMHO sarebbe peggio che vivere con il set + x linee ...
Andreas Spindler

Non vedo come ( set -x \n command \n )sia peggio di set -x \n command \n set +x.
chepner

3
@chepner: non puoi impostare le variabili.
choroba

2
... e non puoi cd: non cambia la directory corrente nella shell genitore.
Andreas Spindler

Mi spiace, non sono sicuro di quale pensassi fosse la tua vera obiezione. È stata una settimana lunga ...
chepner

8

Ho hackerato una soluzione a questo solo di recente quando mi sono infastidito:

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

Ciò consente di abilitare e disabilitare xtrace come di seguito, dove sto registrando come gli argomenti sono assegnati alle variabili:

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

E ottieni un output che assomiglia a:

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

Trucco intelligente (anche se non hai bisogno della /dev/stdinparte). L'avvertenza è che l'attivazione dell'espansione degli alias negli script può avere effetti collaterali indesiderati.
mklement0

Hai ragione. Ho modificato la risposta per rimuovere il superfluo /dev/stdin. Non sono a conoscenza di effetti collaterali specifici, poiché l'ambiente non interattivo non dovrebbe caricare alcun file che definisca gli alias. Quali effetti collaterali potrebbero esserci?
user108471

1
Questo è un buon punto: ho dimenticato che gli alias non vengono ereditati, quindi il rischio è molto minore di quanto pensassi (ipoteticamente, il tuo script potrebbe acquisire codice di terze parti che definisce gli alias, ma sono d'accordo che probabilmente non è un vero- preoccupazione mondiale). +1
mklement0

1
@AndreasSpindler Potresti spiegare perché pensi che questa tecnica abbia maggiori probabilità di far trapelare informazioni più sensibili?
user108471

1
... fondamentalmente perché gli alias e le funzioni sono costrutti di alto livello. set +xè molto più difficile (se non impossibile) scendere a compromessi. Ma è ancora una buona e diretta soluzione, probabilmente la migliore finora.
Andreas Spindler

7

Che ne dici di una soluzione basata su una versione semplificata di @ user108471:

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

trace_on
...stuff...
trace_off

Cosa ne pensi di questo? function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH

1

Questa è una combinazione di alcune idee che possono racchiudere un blocco di codice e preservare lo stato di uscita.

#!/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

Quando eseguito:

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

Bello sforzo ma penso che il ()giro exitnon sia necessario. Ok. Forse questo è paranoico, ma se questo codice viene utilizzato, in generale, si ha un buon vettore di attacco: Ridefinire trace_one trace_offe il codice che legge iniettare comandi eseguiti. Se si utilizzano tali "utilità" da sole è istruttivo, ma se il codice viene utilizzato con altri è necessario considerare se i vantaggi di tali funzioni non standardizzate superano gli svantaggi. Personalmente ho deciso { set +x; } 2>/dev/nullperché questo costrutto è comunemente inteso e anch'esso non cambia lo stato di uscita.
Andreas Spindler il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.