Ich versuche, ein Shell-Skript in Python aufzurufen, aber es meldet gebrochenen Pipefehler (das Ergebnis ist OK, aber ich möchte die Fehlermeldung nicht in STDERR sehen). Ich habe die Ursache ermittelt und sie kann wie folgt reproduziert werden:
subprocess.call('cat /dev/zero | head -c 10 | base64', shell=True)
AAAAAAAAAAAAAA ==
cat: Schreibfehler: Broken pipe
/dev/zero
ist ein unendlicher Stream, aber die head -c 10
liest nur 10 Bytes davon und endet, dann wird cat SIGPIPE bekommen, weil der Peer die Pipe geschlossen hat. Es gibt keine gebrochene Rohr-Fehlermeldung, wenn ich den Befehl in der Shell ausführe, aber warum Python es zeigt?
Die Standardaktion für das SIGPIPE-Signal besteht darin, das Programm zu beenden. Der Python-Interpreter ändert es in SIG_IGN, um gebrochene Rohrleitungsfehler in Form von Ausnahmen an ein Programm melden zu können.
Wenn Sie cat ... |head ...
in der Shell ausführen, hat cat
den standardmäßigen SIGPIPE-Handler und der Betriebssystemkernel beendet ihn nur auf SIGPIPE.
Wenn Sie cat
mit subprocess
ausführen, wird der SIGPIPE-Handler vom übergeordneten (Python-Interpreter) abgeleitet, SIGPIPE wird ignoriert und cat
behandelt den Fehler selbst, indem er errno
variable prüft und eine Fehlermeldung ausgibt.
Um Fehlermeldungen von cat
zu vermeiden, können Sie preexec_fn
Argument für subprocess.call verwenden:
In diesem trivialen Fall gewinnst du zumindest nichts mit Shell-Befehlen - und du verlierst Portabilität und Geschwindigkeit.
Python 2-Code:
%Vor% In Python 3 (Code wird auch in 2.6+ ausgeführt, obwohl er str
anstatt bytes
Instanzen zurückgibt):
In jedem Fall behält das erste Beispiel die Verwendung von /dev/zero
(an sich nicht tragbar, aber egal), die zweite erzeugt den Effekt, obwohl ich mir vorstelle, dass es nicht genau das ist, was Sie wollen?
Tags und Links python bash subprocess