Bash: Entkomme einzelnen Zeilen aus dem Echo von -x


11

Ist es in bash -xmöglich, einzelne Befehle vom Echo auszunehmen, wenn sie mit der Option ausgeführt werden?

Ich versuche, die Ausgabe so ordentlich wie möglich zu gestalten, daher führe ich bestimmte Teile meines Skripts in einer Subshell mit aus set +x. Die Zeile set +xselbst wird jedoch weiterhin wiederholt und fügt der Ausgabe keine wertvollen Informationen hinzu.

Ich erinnere mich, dass in den schlechten alten .batZeiten, als ich mit lief echo on, einzelne Zeilen ausgenommen werden konnten, indem man sie mit a begann @. Gibt es ein Äquivalent 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

Wenn Sie das oben genannte ausführen, lautet die Ausgabe:

+ 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

Antworten:


21

xtraceDie Ausgabe geht an stderr, sodass Sie umleiten können stderrzu /dev/null:

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

Wenn Sie weiterhin die Fehler der Befehle sehen möchten, die in den Funktionen ausgeführt werden, können Sie dies tun

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

Beachten Sie die Verwendung von (...)anstelle von {...}, um einen lokalen Bereich für diese Funktion über eine Subshell bereitzustellen. bash, da Version 4.4 jetzt local -wie in der Almquist-Shell unterstützt, Optionen lokal für die Funktion zu machen (ähnlich wie set -o localoptionsin zsh), können Sie die Subshell vermeiden, indem Sie Folgendes tun:

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

Eine Alternative für bash4.0 bis 4.3 wäre, die $BASH_XTRACEFDVariable zu verwenden und dafür einen dedizierten Dateideskriptor zu öffnen /dev/null:

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

Da bashes nicht möglich ist, ein fd mit dem Close-on-Exec- Flag zu markieren , hat dies den Nebeneffekt, dass dieses fd an andere Befehle weitergegeben wird.

Siehe auch diese locvar.sh der einige Funktionen enthält implementieren lokalen Spielraum für Variablen und Funktionen in POSIX - Skripten und bietet auch mit trace_fnund untrace_fnFunktionen , sie zu machen xtrace d oder nicht.


Süss! Ich habe nach Modifikatoren gesucht, die ich auf die Funktion selbst anwenden kann, aber ich habe nicht daran gedacht, stderr einfach umzuleiten. Vielen Dank!
Clacke

1
Übrigens ist stchaz.free.fr/which_interpreter von derselben Seite ziemlich großartig und verstörend. :-)
Clacke

Und jetzt bin ich wieder hierher zurückgekommen, um die zweite Methode zu verwenden: Set + x stummzuschalten, ohne die nützliche stderr-Ausgabe stumm zu schalten. Danke noch einmal!
Clacke

2

Der Grund, der set +xgedruckt wird, set -xbedeutet: "Drucken Sie den Befehl, den Sie ausführen möchten , mit Erweiterungen aus, bevor Sie ihn ausführen . Die Shell weiß also nicht, dass sie keine Dinge drucken soll, bis sie die Zeile gedruckt hat, in der dies nicht angegeben ist." Dinge zu drucken. Nach meinem besten Wissen gibt es keine Möglichkeit, dies zu verhindern.


0

Hier ist die Lösung, nach der Sie gesucht haben:

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

Der ursprüngliche Befehl wird in derselben Shell unter einer Identitätstransformation ausgeführt. Kurz vor dem Ausführen erhalten Sie eine nicht rekursive xtrace der Argumente. Auf diese Weise können Sie die Befehle, die Ihnen wichtig sind, verfolgen, ohne stederr mit doppelten Kopien jedes "echo" -Befehls zu spammen.

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

Oder um zu vermeiden perl(und Probleme mit mehrzeiligen Befehlen):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Stéphane Chazelas

Nein, sorry, unix.stackexchange.com/a/60049/17980 ist die Lösung, nach der ich gesucht habe. :-) set -xKaufen mir die Manöver etwas im Vergleich zu nur printf >&2 '+ %s\n' "$*"?
Clacke

Wie in:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
Clacke
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.