Ich habe versucht, eine Antwort auf diese Frage zu finden, aber bisher kein Glück gehabt:
Ich habe ein Skript, das einige andere Skripte ausführt, und viele dieser anderen Skripte enthalten "set -x", wodurch sie jeden von ihnen ausgeführten Befehl drucken. Ich möchte das loswerden, aber die Informationen behalten, wenn eines der Skripte die Fehlermeldung an stderr sendet.
Also kann ich nicht einfach schreiben ./script 2>/dev/null
Außerdem habe ich keine Berechtigung zum Bearbeiten dieser anderen Skripts, sodass ich die festgelegte Option nicht manuell ändern kann.
Ich habe darüber nachgedacht, alles von stderr in die separate Datei zu protokollieren und die Tracing-Befehle herauszufiltern, aber vielleicht gibt es einen einfacheren Weg?
./script 2>some_file
Antworten:
Mit
bash
4.1 und höher ist dies möglich(Funktioniert auch, wenn
bash
aufgerufen wird alssh
).Grundsätzlich empfehlen wir,
bash
diextrace
Ausgabe auf Dateideskriptor 7 anstatt auf Standard 2 auszugeben und diesen Dateideskriptor auf umzuleiten/dev/null
. Die fd Nummer ist beliebig. Verwenden Sie ein FD über 2, das in Ihrem Skript nicht anders verwendet wird. Wenn die Shell, in der Sie diesen Befehl eingeben,bash
oder istyash
, können Sie sogar eine Zahl über 9 verwenden (obwohl Probleme auftreten können, wenn der Dateideskriptor intern von der Shell verwendet wird).Wenn die Shell, von der aus Sie das
bash
Skript aufrufen, istzsh
, können Sie auch Folgendes tun:für die Variable wird automatisch das erste freie fd über 9 vergeben.
Für ältere Versionen
bash
, eine andere Option, wenn diextrace
mit eingeschaltet wirdset -x
(im Gegensatz zu#! /bin/bash -x
oderset -o xtrace
) wäre neu zu definierenset
als eine exportierte Funktion , die nichts tut , wenn übergeben-x
(obwohl das das Skript brechen würde , wenn er (oder irgendein anderesbash
Skript sie aufruft) verwendet , umset
die Positionsparameter einzustellen).Mögen:
Eine andere Option ist das Hinzufügen eines DEBUG-Traps in einer
$BASH_ENV
Datei, dieset +x
vor jedem Befehl ausgeführt wird.Das geht aber nicht, wenn
set -x
in einer Sub-Shell gearbeitet wird.Wie @ilkkachu sagte, sollten Sie, vorausgesetzt, Sie haben Schreibberechtigung für einen Ordner im Dateisystem, zumindest in der Lage sein, eine Kopie des Skripts zu erstellen und es zu bearbeiten.
Wenn Sie nirgendwo eine Kopie des Skripts schreiben können oder wenn es nicht bequem ist, bei jeder Aktualisierung des Originalskripts eine neue Kopie zu erstellen und zu bearbeiten, können Sie möglicherweise folgende Aktionen ausführen:
Dies (und der Kopieransatz) funktioniert möglicherweise nicht richtig, wenn das Skript etwas
$0
Besonderes mit oder spezielle Variablen ausführt$BASH_SOURCE
(z. B. nach Dateien suchen, die sich auf den Speicherort des Skripts selbst beziehen), sodass Sie möglicherweise noch etwas nachbearbeiten müssen Ersetzen Sie$0
mit dem Pfad des Skripts ...quelle
{BASH_XTRACEFD}>
Trick funktioniert auch inbash
4.1 oder höher.ksh93
oderbash
dadurch , dass der Variable in der Umgebung des Befehls nicht bestanden (vergleiche<shell> -c 'export fd; printenv fd {fd}> /dev/null'
inzsh
,bash
undksh93
). Man kann es in machen arbeitenksh93
/bash
indem sie sie in zwei Schritten tun oder möglicherweise unter Verwendungeval
, sondern auch fürbash
, die Nebenwirkungen , wenn die xtrace Option war hätte.Da sie Skripte sind, Sie könnten Kopien von ihnen machen, und bearbeiten diese.
Abgesehen davon, dass das Filtern der Ausgabe einfach erscheint, können Sie explizit
PS4
etwas Ungewöhnlicheres als ein einzelnes Plus festlegen , um das Filtern zu vereinfachen:(Natürlich wird das stdout und stdin kollabieren, aber das Leiten von nur stderr in Bash wird ein bisschen haarig, also werde ich das ignorieren.)
quelle
PS4="%%%%" bash script.sh 2> >(grep -ve '^%%%%')
.bash
hat Probleme, dagrep
es asynchron ausgeführt wird (bash wartet nicht darauf, sodass es Dinge ausgeben kann (und dies auch oft tut), nachdem der nächste Befehl im Skript gestartet wurde).