bash: evita le singole linee dall'eco `-x`


11

In bash, quando si esegue con l' -xopzione, è possibile esentare i singoli comandi dall'eco?

Sto cercando di rendere l'output il più pulito possibile, quindi sto eseguendo alcune parti del mio script in una subshell con set +x. Tuttavia, la riga set +xstessa viene ancora ripetuta e non aggiunge informazioni preziose all'output.

Ricordo che ai vecchi .battempi, quando correvo echo on, le singole linee potevano essere esentate avviandole con un @. C'è qualche equivalente in 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

Quando si esegue quanto sopra, l'output è:

+ 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

Risposte:


22

xtracel'output va su stderr, quindi puoi reindirizzare stderra /dev/null:

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

Se vuoi ancora vedere gli errori dai comandi eseguiti all'interno delle funzioni, puoi farlo

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

Si noti l'uso di (...)invece di {...}fornire un ambito locale per quella funzione tramite una subshell. bash, poiché la versione 4.4 ora supporta local -come nella shell Almquist per rendere le opzioni locali alla funzione (simile a set -o localoptionsin zsh), quindi è possibile evitare la subshell facendo:

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

Un'alternativa da bash4.0 a 4.3 sarebbe usare la $BASH_XTRACEFDvariabile e avere un descrittore di file dedicato aperto /dev/nullper quello:

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

Dal momento che bashmanca la possibilità di contrassegnare un fd con il flag close-on-exec , ciò ha l'effetto collaterale di perdere quel fd ad altri comandi.

Vedi anche questo locvar.sh che contiene alcune funzioni per implementare l' ambito locale per variabili e funzioni negli script POSIX e fornisce anche trace_fne untrace_fnfunzioni per renderle xtrace o meno.


Dolce! Stavo cercando di vedere se ci fossero dei modificatori che potrei applicare alla funzione stessa, ma non ho pensato di reindirizzare semplicemente stderr. Grazie!
Clacke

1
A proposito, stchaz.free.fr/which_interpreter dalla stessa pagina è piuttosto fantastico e inquietante. :-)
clacke

E ora sono tornato di nuovo qui per il secondo metodo, silenziando set + x senza mettere a tacere l'utile output stderr. Grazie ancora!
clacke

2

Il motivo che set +xviene stampato è che set -xsignifica "stampare il comando che si sta per eseguire, con le espansioni, prima di eseguirlo . Quindi la shell non sa che si desidera che non stampi le cose fino a quando non ha stampato la riga dicendo che non lo fa per stampare le cose. Per quanto ne so, non c'è modo di impedire che ciò accada.


0

Ecco la soluzione che stavi cercando:

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
  "$@"
}

Il comando originale viene eseguito nella stessa shell con una trasformazione dell'identità. Appena prima dell'esecuzione, si ottiene una xtrace non ricorsiva degli argomenti. Questo ti permette di tracciare i comandi che ti interessano senza spammare Stederr con copie duplicate di ogni comando "echo".

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated

O per evitare perl(e problemi con i comandi multilinea):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Stéphane Chazelas il

No, scusa, unix.stackexchange.com/a/60049/17980 è la soluzione che stavo cercando. :-) Le set -xmanovre mi comprano qualcosa rispetto a solo printf >&2 '+ %s\n' "$*"?
clacke,

Come in:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
clacke
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.