subprocess.popen -> Ausgabe anzeigen und weiterverarbeiten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
BlackJack

Freitag 23. März 2012, 16:14

@mcdaniels: Zur Präzisierung mit den Argumenten: Du musst eine Liste übergeben welche die Argumente einzeln enthält, so wie sie eine Shell dem Programm beim Aufruf übergeben würde. Und '-s acert.p12 -p Passwort' ist nicht *ein* Argument sondern *vier*. Die Shell teilt so etwas in der Regel an Leerzeichen auf wenn man es nicht „schützt”, zum Beispiel in dem man ein Argument in Anführungszeichen einfasst oder einzelne Leerzeichen mit einem '\' „escape”t.

Der Vorteil und damit der Grund warum man bei `Popen` diese Liste übergibt, liegt darin, dass jedes Element so übergeben wird, wie es in den einzelnen Elementen angegeben ist. Ohne das eine Shell da noch einmal drüber geht und bestimmte Zeichen besonders interpretiert. Im Umkehrschluss kann man auch alle Zeichen so angeben wie sie beim aufgerufenen Programm ankommen sollen, ohne dass man sich Gedanken machen muss bestimmte Zeichen vor einer Shell zu schützen, weil die für eine Shell eine Sonderbedeutung haben. Das betrifft zum Beispiel Leerzeichen in Dateinamen oder Sonderzeichen bei Passwörtern.
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Freitag 23. März 2012, 19:12

Hallo!
Ein Punkt ist: '-o' ist nicht gleich ' -o '.
'-o ' deshalb, da ich dachte ich könnte auch Leerzeilen übergeben.
Passiert denn noch irgendwas darüber hinaus? Also sozusagen etwas pythonspezifisches? Bisher sieht dein Code nämlich so aus, als ahmst du Shellprogrammierung mit Python nach. Nicht mal das: Du rufst Shellprogramme (wie `copy` und `del`) über Python auf, wo Python für Dateioperationen usw reichlich Funktionalität mitbringt und dafür nicht auf externe Programme angewiesen ist. Da möchte man in der Tat die Hände über den Kopf zusammenschlagen.
Nein, es passiert sonst eigentlich nichts pythonspezifisches. Allerdings soll das ja auf keinen Fall die Endfassung sein. Das ist das, was ich mir jetzt wortwörtlich "zusammengeschustert" habe. Ich war froh, dass es das tut, was es soll ;) - man braucht als Anfänger solche Erlebnisse... Es ist halt die "Idee" eines Anfängers. Nachdem ich bislang leider mit subprocess gescheitert bin, hab ich als ersten Lösungsweg mal den "unsauberen" über die OS Befehle bzw. das Modul system genommen.

Python habe ich deshalb genommen, weil ich es: a.) als eine interessante Aufgabenstellung sehe und b.) auch wenn ich in Python leider noch immer weit weg vom Status eines Anfängers bin, glaube ich, dass die Problemlösung in Python eleganter von statten geht wie in einer Batchdatei.

Es ist "spannender" ein Ziel vor Augen zu haben (Programm), welches im Endeffekt dann auch genutzt werden kann. Z.b. besser als nur Beispielprogramme zu erstellen, die im Endeffekt keinen Nutzen haben. Dummerweise wird mein Pythonengagement immer wieder unterbrochen (wenig Zeit wg. dem Beruf), weshalb ich offenbar kaum vom Fleck komme.

Ich finde das Forum hier übrigens super und möchte mich hier nochmal für eure konstruktive Kritik und eure Geduld bedanken!

LG
Daniel
BlackJack

Samstag 24. März 2012, 07:15

@mcdaniels: Mit `subprocess` (ungetestet):

Code: Alles auswählen

import os
from glob import glob
from subprocess import PIPE, Popen


def main():
    for pdf_filename in glob('*.pdf'):
        target_path = os.path.join(
            'sig-pdf', os.path.splitext(pdf_filename)[0] + '_sig.pdf'
        )
        print pdf_filename, '->', target_path
        process = Popen(
            [
                'java',
                '-jar', 'PortableSigner.jar',
                '-b', 'de',
                '-c', 'Dieses Dokument wurde amtssigniert. Informationen zur'
                        ' Pruefung finden Sie unter <url einfuegen>',
                '-i', 'Bildmarke.jpg',
                '-n',
                '-t', pdf_filename,
                '-o', target_path,
                '-s', 'acert.p12',
                '-p', 'Passwort'
            ]
            stdout=PIPE
        )
        output, _ = process.communicate()
        return_code = process.wait()
        print 'Return code:', return_code
        print 'Output:'
        print output


if __name__ == '__main__':
    main()
Das Ergebnis wird gleich in das richtige Verzeichnis geschrieben, so dass man keine Verschiebefunktion braucht. Dafür hätte man statt `os.ystem()` mit Hilfe des `shutil`-Moduls etwas Systemunabhängiges schreiben können.

(Die URL habe ich rauseditiert, weil der doofe Syntaxhighlighter vom Forum da Mist baut.)
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Montag 26. März 2012, 09:58

Hallo blackjack!

Danke dir für deinen Entwurf. Es hat nur ein Beistrich vor stdout gefehlt. Und ich habe die Printfunktion angepasst (da Python 3):

Code: Alles auswählen

import os
from glob import glob
from subprocess import PIPE, Popen


def main():
    for pdf_filename in glob('*.pdf'):
        target_path = os.path.join(
            'sig-pdf', os.path.splitext(pdf_filename)[0] + '_sig.pdf'
        )
        print (pdf_filename, '->', target_path)
        process = Popen(
            [
                'java',
                '-jar', 'PortableSigner.jar',
                '-b', 'de',
                '-c', 'Dieses Dokument wurde amtssigniert. Informationen zur'
                        ' Pruefung finden Sie unter <url einfuegen>',
                '-i', 'Bildmarke.jpg',
                '-n',
                '-t', pdf_filename,
                '-o', target_path,
                '-s', 'acert.p12',
                '-p', 'Passwort'
            ]
            ,stdout=PIPE
        )
        output, _ = process.communicate()
        return_code = process.wait()
        print ('Return code:', return_code)
        print ('Output:')
        print (output)


if __name__ == '__main__':
    main()
Jetzt muss ich nur noch verstehen, was dein Programm exakt macht. :) Die PDFs werden ordnungsgemäß signiert.

Als Output bekomme ich u.a.:


Return code: 0 (klar)
Output:
b'' (nicht klar)


LG
Daniel
BlackJack

Montag 26. März 2012, 10:25

@mcdaniels: Was ist daran nicht klar?

Was es ist? → Die Bytes die das Signierprogramm auf seiner Standardausgabe ausgibt.

Das es Bytes statt Zeichen sind? → Über die Standardein- und ausgaben, sowie in und aus Dateien kann man nur Bytes schreiben und lesen, da im Allgemeinen nicht automatisch ermittelt werden kann in welcher Kodierung diese Daten gelesen und geschrieben werden sollen, wenn es denn überhaupt Texte sind, die man sinnvoll als Unicode-Zeichenketten darstellen kann.

Das es leer ist? → Falls das Signierprogramm etwas ausgibt, dann anscheinend nicht über seine Standardausgabe, sondern über die Standardfehlerausgabe. Dann muss man `stderr` bei `Popen` umleiten und das zweite Element vom `communicate()`-Rückgabewert auswerten.
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Montag 26. März 2012, 10:38

@blackjack: Danke für deine Ausführungen. Im Endeffekt ist die Ausgabe insofern nicht wichtig, da es funktioniert. Eventuell sollte man noch stderr auswerten.

Andre Frage: wie bekommst du beim pdf_filename das .pdf weg: EDIT -> grade gesehen das macht splittext. (Ist ja doch zu etwas gut das Büchlein Python gepackt :) ) Oft hab ich das Problem, dass ich nicht weiß, welche Befehle für diverse Problemlösungen herangezogen werden. Trotz dem Buch und der Python Befehlsreferenz (Python Standard Library). Ich denke, das Problem wird wohl mit der Zeit verschwinden, wenn ich es denn nun endlich mal schaffe, dabei zu bleiben...

LG
Daniel
Benutzeravatar
/me
User
Beiträge: 3262
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Montag 26. März 2012, 11:03

mcdaniels hat geschrieben:Andre Frage: wie bekommst du beim pdf_filename das .pdf weg: EDIT -> grade gesehen das macht splittext.
'splittext'.replace('tt', 't')
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Montag 26. März 2012, 11:07

Danke /me für die Details zu splittext.
Benutzeravatar
/me
User
Beiträge: 3262
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Montag 26. März 2012, 11:18

mcdaniels hat geschrieben:Danke /me für die Details zu splittext.
Gemeint war eigentlich, dass es splitext heißt wie in "split extension", nicht splittext wie in "split text".
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Montag 26. März 2012, 11:21

...wer lesen kann, ist klar im Vorteil :oops:
Antworten