Stderr-Nachrichten in einem Bash-Skript unterdrücken

48

Betrachten Sie den folgenden (etwas albernen) Skriptnamen 'test1.sh':

#/bin/bash
#
sleep 10 &
echo sleep pid = $!
pkill sleep

Wenn ich es starte, erhalte ich nicht nur die Ausgabe des Echos, sondern auch die bash-Meldung über den Tod des Schlafes auf stderr:

$ ./test1.sh
sleep pid = 3551
./test1.sh: line 5:  3551 Terminated              sleep 10

In diesem Fall möchte ich den Ausdruck auf stderr unterdrücken. Ich weiß, dass ich es auf der Kommandozeile machen kann, wie in:

$ ./test1.sh 2> /dev/null

... aber ist es eine Möglichkeit , es aus zu unterdrücken , in dem Skript? (Ich weiß, ich könnte es in ein zweites Skript einbinden und den Wrapper umleiten lassen, aber es muss etwas einfacher sein ...)

furchtloser Dummkopf
quelle
Haben Sie versucht, die Umleitung 2> / dev / null nach dem Pkill Sleep hinzuzufügen?
Rahul
@rahul: ja, ich habe es getan - pkill generiert die Nachricht nicht, bash ist.
fearless_fool
Ich habe kill anstelle von pkill verwendet und bekomme nicht die stderr. seltsam ..
Rahul
@rahul: könnte es ein eingebautes oder ein nicht eingebautes Ding sein? Hast du es auch mit pkill versucht?
fearless_fool
Ja, ich glaube es ist. Ich bekomme den gleichen Fehler mit pkill, aber nicht mit kill. Bei der Verwendung von Kill habe ich die PID anstelle des Proc-Namens verwendet.
Rahul

Antworten:

72

Du hast recht; pkill generiert die Nachricht nicht, bash ist. Sie schlagen das vor

$ ./test1.sh 2> /dev/null

ist eine mögliche Lösung. Wie UVV hervorhebt, ist die entsprechende Aktion innerhalb des Skripts

exec 2> /dev/null

Das leitet das stderr für das Skript /dev/null von dieser Anweisung weiter, bis es wieder geändert wird. Unbeholfene Möglichkeiten, es wieder zu ändern, umfassen

exec 2> /dev/tty

welches stderr zum terminal umleitet. Dies ist wahrscheinlich (aber nicht unbedingt) der Ort, an dem es ursprünglich war.

Oder

exec 2>&1

Das setzt stderr auf das Gleiche wie stdout und ist wahrscheinlich falsch.

Ein zuverlässigerer Weg ist

Exec 3> & 2
exec 2> / dev / null
(Mach Sachen, bei denen du die stderr nicht sehen willst.) 
exec 2> & 3

Dadurch wird das ursprüngliche stderr in Dateideskriptor 3 gespeichert und später wiederhergestellt.

Andere Möglichkeiten, nur die Ankündigung des Todesprozesses zu unterdrücken, umfassen

(sleep 10 & pkill sleep) 2> /dev/null

und

{ sleep 10 & pkill sleep;} 2> /dev/null

die das stderr nur für die gruppierten Befehle ändern.

Scott
quelle
Dies ist eine großartige, detaillierte Antwort. Danke mein Herr!
Keenan Lawrence
Gibt es Gefahren beim Speichern stdinund Wiederherstellen stderrneuer Dateideskriptoren, indem die ursprünglichen Deskriptoren an /dev/nulldiese gesendet und anschließend wiederhergestellt werden?
Alexej Magura
Nun, ich nehme an, dass diese Operation unter normalen Umständen fehlschlagen würde, wenn Sie ein Programm ausführen, das (ohne Ihr Wissen) in den Dateideskriptor 3 (oder 4) geschrieben hat. Aber das Programm könnte geschrieben werden, um den Fehler zu ignorieren und fortzufahren, ohne ihn zu melden. dann wüsstest du es nie. Wenn Ihr Dateideskriptor 1 (oder 2) auf Dateideskriptor 3 (oder 4) "geparkt" wurde, schreibt dieses Programm plötzlich in die Standardausgabe oder die Standardausgabe Ihres Skripts. Aber das ist ein sehr ausgeklügeltes Beispiel und dennoch eine minimale Gefahr. Hattest du etwas im Sinn?
Scott
1
FWIW, ich bevorzuge Scotts Gruppenkommando-Ansatz, dh{ sleep 10 & pkill sleep;} 2> /dev/null
fearless_fool
9

Nach dieser könnte man so etwas wie folgt vorgehen:

#!/bin/bash
exec 2>/dev/null
ls -al test
UVV
quelle