Seite 1 von 1

Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 18:47
von ravenheart
Hallo, nachdem os.system() deprecated ist, wollte ich eine Funktion schreiben, welche für mich das selbe tut.

Sprich, ich gebe einen String an, der dann wie in der Konsole ausgeführt wird.

shell_exec("cat test.txt | grep -v abc") zB

Leider haperts mit dem Ding noch etwas: ich bekomme anscheinend wahllos viele Leerzeilen am Schluss zu viel ausgegeben.

Wenn ich beispielsweise eine Textdatei mit folgendem Inhalt habe:
Lorem Ipsum
erhalte ich nach dem Aufruf von shell_exec("cat test.txt") folgendes Ergebnis
Lorem Ipsum

Mit 2 Leerzeilen am Schluss. Nunja, die Frage ist: Was muss ich ändern um dieses Verhalten zu vermeiden?
HIer der enstprechende Code:

Code: Alles auswählen

# -*- coding: utf-8 

### Imports ### 
import os 
import sys 
import shlex 
import subprocess 

def shell_exec(command): 
        cmds = command.split("|") 
        cmds = [ cmd.strip() for cmd in cmds] 
        cmds = map(shlex.split, cmds) 

        procs = [] 
        prev_out = sys.stdin 

        for cmd in cmds: 
                proc = subprocess.Popen(cmd, stdin=prev_out, stdout=subprocess.PIPE) 
                prev_out = proc.stdout 
                procs.append(proc) 

        (stdout, stderr) = procs[-1].communicate() 

        for proc in reversed(procs): 
                proc.wait() 

        print(stdout)

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 18:56
von cofi
`os.system` ist nicht deprecated, sondern `subprocess` wird empfohlen.

Fuer dein Problem: http://docs.python.org/library/subproce ... -os-system

Wichtig is dabei das `shell=True`. Das musst du nicht selbst implementieren.

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 19:02
von snafu
@cofi:

Wenn man aber die genannte Syntax nutzen möchte, ohne die Unsicherheiten einer implizit benutzten Shell zu haben, sollte man eben kein `shell=True` setzen, sondern es durchaus selbst implementieren.

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 19:18
von ravenheart
Also, ich hab das ganze ja meiner Meinung nach recht weit, nur dass ich irgendwie seltsame Ergebnisse bekomme in gewissen Fällen, bisher habe ich nur überflüssige Leerzeilen feststellen können.

Aber selbst das könnte in manchen Anwendungsfällen zu Problemen führen.

Konkret suche ich also nun eine Verbesserung meines Codes, so dass dieser stabil läuft.
Wichtig ist mir vor allem auch dass Pipes anwendbar sind.

Ich finde leider keinen Fehler, euer Rabenherz

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 20:00
von Leonidas
Und normalerweise nutzt man ``shell=False`` (was eh der Standardwert ist) eben weil man nicht so Programme wie grep reinhängen sollte sondern so "triviale" Funktionalität besser in Python löst.

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 20:16
von ravenheart
Hmmm, dass ich höchstwahrscheinlich nicht grep verwenden möchte, ist eigentlich klar.
Es geht mir auch nicht darum, was ich mit damit jetzt tatsächlich anstelle. Es sei nur gesagt, dass es durchaus Sinn macht, diese Funktion zu haben.

Ich suche auch nicht nach Möglichkeiten Dinge, die ich über Shell oder Subprocess ablaufen lassen will, durch Python zu ersetzen.
Einzig und allein die Fehlerursache und vor allem die Behebung sind Sinn und Zweck des Threads.

Die verwendeten Funktionen sind hier so einfach wie möglich gehalten um gewünschte Funktionalität und Fehlerbeschreibung anzugeben.

Also nochmal wiederholen, bevor der Thread noch in eine von mir nicht gewünschte Richtung abschweift.

Ich möchte eine Funktion haben, welche aud subprocess basiert, welche einen String erwartet und dieses mehr oder weniger so ausführt, als wenn der String in der Konsole geschrieben worden wäre.

Mein Ansatz ist oben beschrieben, aber fehlerhaft.

Nun ist eine Korrektur erwünscht.

Danke!
(das ist keinesfalls ironisch oder böswillig gemeint)

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 20:21
von Leonidas
Dann reicht mehr oder weniger ``subprocess.call``...

Re: Subprocess Problem

Verfasst: Mittwoch 10. November 2010, 20:27
von ravenheart
Hmm, ich kann das gerade nicht testen,
aber wenn ich die Doc ansehen, scheint mir als wenn man Befehl und Argumente getrennt in einer Liste angeben müsste. Das wäre für meine Zwecke höchst ungeeignet ... naja eher sehr umständlich.

Weiterhin: wie sieht es da mit Pipes aus?
Ich kann leider im Beispiel nichts dergleichen erkennen.

Meinen Versuch habe ich an

Code: Alles auswählen

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
von http://docs.python.org/library/subprocess.html
angelehnt.

Edit: ok, das mit dem Trennen zu einer Liste übernimmt shlex für mich, aber mit den Pipes sehe ich immer noch schwarz.

Um vielleicht das Fenster noch mehr einzuengen:

Es interessiert mich brennend, warum meine Variante nicht tut was sie soll.
Seek and destroy ... Wo liegt der (Denk) Fehler?

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 05:43
von snafu
Ich würde das etwas kürzer schreiben:

Code: Alles auswählen

from shlex import split
from subprocess import PIPE, Popen

def runcmd(cmdline):
    proc = None
    for cmd in cmdline.split('|'):
        if not proc:
            # first process
            proc = Popen(split(cmd), stdout=PIPE)
        else:
            # further procs read from previous ones
            proc = Popen(split(cmd), stdin=proc.stdout, stdout=PIPE)

    output, errors = proc.communicate()
    return output
Gibt dann als Ergebnis:

Code: Alles auswählen

>>> with open('test.txt', 'w') as f: f.write('Lorem Ipsum\n')
>>> runcmd('cat test.txt')
'Lorem Ipsum\n'
Zu deiner Frage mit den Leerzeilen: Also wenn ich deine Funktion in IPython aufrufe, bekomme ich auch 2 Leerzeilen - eine von `print` und eine von IPython.

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 11:55
von ravenheart
Jo, danke . Ich hatte mich schon gewundert ,warum manchmal eine manchmal 2 Leerzeilen zu viel waren. Das lag daran, dass ich manchmal ipython verwendet hab und manchmal nicht.

Das Problem hab ich jetzt behoben , indem ich die print(,end="") funktion nehme.


Eine Sache, die ich gerne hätte, aber im Moment noch nicht zu verwirklichen weiß:

Code: Alles auswählen

echo hello > file.txt
Ich würde gerne auch solche Befehle ausführen können, nur wie kann ich diese abfangen?
Hierbei bin ich leider total überfragt, da ich ja unterscheiden müsste, in welchem Kontext das '>' auftritt.

Falls es hier eine einfache Möglichkeit gibt, ohne dass ich etwas wie einen Parser schreiben muss, wäre ich sehr erfreut.

TY

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 12:15
von BlackJack
@ravenheart: Da wird wohl kein Weg drumherum führen. Wenn Du beliebige Eingaben dort verarbeiten können möchtest, hat Dein aufteilen an '|' ja sowieso schon ein Problem, zu Beispiel bei "echo '|foo|'", oder etwas komplexer: "xterm -e 'cat sig.txt | grep -i python; read'".

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 12:46
von ravenheart
hmm... gibt es so einen parser schon vorgefertigt?

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 12:53
von BlackJack
@ravenheart: Die meisten Shells machen das schon für Dich. ;-)

Was ist denn überhaupt der Anwendungsfall? Warum musst oder willst Du Shell-Syntax selber parsen, anstatt einfach tatsächlich eine Shell zu benutzen?

Und wie weit soll das gehen? Was ist mit in der Shell eingebauten Kommandos wie zum Beispiel ``cd``? Oder Variablen (``cd $TEMP``)?

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 13:02
von ravenheart
Du hast Recht...
bevor ich mich jetzt in etwas hineinsteigere, sollte ich mir doch Gedanken darüber machen, ob das notwendig ist.

Das ganze ist nur dadurch entstanden, dass ich in der Python-doc gelesen habe, dass man os.system - Befehle besser ersetzt.

Für meinen Anwendungsfall ist es aber unerheblich, was ich letztendlich benutze, solange keine Fehler auftreten.

Ich denke ich belasse das ganze einfach mal so und entscheide je nach Situation, ob ich meine neue Funktion oder os.system nutze.

Dieses ganze Gefrickel lenkt mich nur von meiner eigentlichen Arbeit ab.

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 14:24
von BlackJack
@ravenheart: Es gäbe ja noch den Mittelweg: Auf `os.system()` verzichten und `subprocess` verwenden, da aber eben über die Shell gehen. Also zum Beispiel ``subprocess.call("foo $WHATEVER | grep 'solution:' > result.txt", shell=True)``.

Re: Subprocess Problem

Verfasst: Donnerstag 11. November 2010, 14:27
von jerch
Dein Ansatz würde halt auf das Nachbauen der Shellfunktionalitäten hinauslaufen, z.B. eine Art bash.py ;)
Nun sind die Shells nicht über Nacht entstanden und bringen eine unüberschaubare Funktionsvielfalt mit. Selbst mit der Umsetzung eines Subsets der Funktionen dürftest Du eine Weile beschäftigt sein.

Das Unixkonzept lebt gerade von der Idee der kleinen Tools und Helferlein, die mit dem Schweizer Taschenmesser "Shell" ihre Wirkung entfalten können. Windows-Administratoren können hiervon ein Klagelied singen (gut mit der Powershell ist das dort besser geworden, allerdings wird die neue Syntax von vielen abgelehnt und die Funktionen liegen daher brach, ganz zu schweigen von den Unzulänglichkeiten des Windows-"Terminals").

@os.system:
Ich bin kein kategorischer Gegner von 'system()', allerdings sollte man die Fallstricke der Funktion kennen (siehe 'man system').

Shellscripting ist ein mächtiges Werkzeug in der unixoiden Welt. Manchmal ist es eben einfacher, die Shell und die unzähligen Systemtools zu benutzen, denn hierfür wurden die Tools kreiert. Man ist allzu schnell verleitet, diese Funktionen mit ellenlangem Code in der Programmiersprache der Wahl nachzubauen (Skriptsprachen wie Python oder Perl vorallem), wo die Shell mit einem Einzeiler aufwartet. Manchmal hilft es, nicht Python als "Zentralinstanz" zum Abarbeiten des Problems zu sehen, sondern die Shell hierfür zu nutzen und den Interpreter bei Bedarf hinzuzunehmen.

Die sicherheitskritische Betrachtung der Shellbenutzung hab ich mal ausser Acht gelassen. Sie ist durchaus ein Grund, die Funktionen teilweise nachbilden zu wollen, um ohne "echte" Shell auszukommen. Selbiges gilt für Plattformunabhängigkeit.