2016-05-31 14 views
1

Ich versuche, mehrere Bash-Routinen von einer GUI-basierten Software zu starten. Das Problem, mit dem ich konfrontiert bin, ist ein Problem mit der Verrohrung. Hier der Test Bash-Skript (bashScriptTest.sh):Broken-Pipe-Fehler Python-Subprozess

#!/bin/bash 
#---------- Working 
ls | sort | grep d > testFile.txt 
cat testFile.txt 
#---------- NOT working 
echo $RANDOM > testFile2.txt 
for i in `seq 1 15000`; do 
    echo $RANDOM >> testFile2.txt 
done 
awk '{print $1}' testFile2.txt | sort -g | head -1 

Und hier das Python-Skript, das den Fehler erzeugt:

import subprocess 
# 
with open('log.txt','w') as outfile: 
    CLEAN=subprocess.Popen("./bashScriptTest.sh", stdout=outfile, stderr=outfile) 
    print CLEAN.pid 
    OUTSEE=subprocess.Popen(['x-terminal-emulator', '-e','tail -f '+outfile.name]) 

Wie Sie läuft das Python-Skript sehen können, die Broken-Pipe-Fehler ist aufgetreten nicht in den ersten drei Rohren (erste Zeile), sondern nach der großen Arbeit von awk getan. Ich muss eine große Menge von Routine und Subroutinen in Bash verwalten und auch mit der Shell == True Flag ändert sich nichts. Ich habe versucht, alles auf die pythonischste Art und Weise zu schreiben, aber leider gibt es keine Chance, ich kann alle Piping-Schritt in Python neu schreiben. Eine andere Sache zu erwähnen ist, dass, wenn Sie das Bash-Skript in einem Terminal testen, alles gut funktioniert. Jede Hilfe würde wirklich geschätzt werden. Danke im Voraus!

EDIT 1:

Die Log-Datei mit dem Fehler sagt:

bashScriptTest.sh 
log.txt 
stack.txt 
testFile2.txt 
test.py 
3 
sort: write failed: standard output: Broken pipe 
sort: write error 
+0

Bitte geben Sie die Fehlermeldung und Stack-Trace hinzuzufügen! :) –

+0

Wann warten Sie, bis die Prozesse enden? –

+0

@ AndréLaszlo Ich habe die Frage bearbeitet! – Mat

Antwort

1

Okay, so ist dies ein bisschen dunkel, aber es passiert einfach so, dass ich auf ein ähnliches Problem lief während forschen ein question on the python-tutor mailing list vor einiger Zeit.

Der Grund, warum Sie bei der Ausführung Ihres Skripts über das Unterprozessmodul (in Python) vs. bash ein anderes Verhalten sehen, ist, dass Python die Disposition von SIGPIPEs für alle untergeordneten Prozesse (global) auf SIG_IGN (ignore) überschreibt.

Wenn die folgende Pipeline ausgeführt wird ...

awk '{print $1}' testFile2.txt | sort -g | head -1 

... head beendet, nachdem sie die erste Zeile von stdout vom sort Befehl gibt, aufgrund der -1 Flagge. Wenn der Befehl sort versucht, mehr Zeilen in sein Stdout zu schreiben, wird ein SIGPIPE ausgelöst.

Die Standardaktion eines SIGPIPE; wenn die Pipeline beispielsweise in einer Shell-ähnlichen Bash ausgeführt wird; ist, den Sortierbefehl zu beenden.

Wie bereits erwähnt, überschreibt python die Standardaktion mit SIG_IGN (ignore), so dass wir mit diesem bizarren und etwas unerklärlichen Verhalten enden.


Das ist alles gut und gut, aber Sie könnten sich fragen, was jetzt zu tun ist? Es hängt von der Version von Python ab, die Sie verwenden ...

Für Python 3.2 und höher sind Sie bereits festgelegt. subprocess.Popen in 3.2 hinzugefügt der restore_signals Parameter, der standardmäßig True ist, und löst das Problem effektiv ohne weitere Maßnahmen.

Für frühere Versionen können Sie ein aufrufbares preexec_fn Argument von subprocess.Popen, wie in ...

import signal 
def default_sigpipe(): 
    signal.signal(signal.SIGPIPE, signal.SIG_DFL) 

# ... 

with open('log.txt','w') as outfile: 
    CLEAN=subprocess.Popen("./bashScriptTest.sh", 
          stdout=outfile, stderr=outfile 
          preexec_fn=default_sigpipe) 

Ich hoffe, dass hilft!

EDIT: Es sollte wahrscheinlich bemerkt werden, dass Ihr Programm tatsächlich ordnungsgemäß funktioniert, AFAICT, wie es ist. Sie sehen nur zusätzliche Fehlermeldungen, die Sie normalerweise nicht sehen würden, wenn Sie das Skript in einer Shell direkt ausführen (aus den oben genannten Gründen). Auch

Siehe:

+0

Danke wirklich viel ... es hat mein Problem behoben, wirklich seltsames Problem für Python. Froh, dass sie während der Entwicklung gelöst – Mat

+0

Ihre 'default_sigpipe()' -Funktion ändert den Zustand global. Ich denke, das ist ein Fehler. Wenn Sie dies einmal tun, haben Sie den gleichen Effekt: 'signal.signal (signal.SIGPIPE, signal.SIG_DFL)' – aramaki