De uitvoer van subprocess.call() ophalen

Hoe kan ik de uitvoer van een procesuitvoering krijgen met subprocess.call()?

Het doorgeven van een StringIO.StringIOobject aan stdoutgeeft deze fout:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 588, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 945, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: StringIO instance has no attribute 'fileno'
>>> 

Antwoord 1, autoriteit 100%

Als je Python-versie >= 2.7 hebt, kun je subprocess.check_output gebruiken die in feite precies doet wat je wilt (het retourneert standaarduitvoer als string).

Eenvoudig voorbeeld (linux-versie, zie opmerking):

import subprocess
print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"])

Merk op dat het ping-commando de linux-notatie gebruikt (-cvoor telling). Als je dit op Windows probeert, vergeet dan niet om het te veranderen in -nvoor hetzelfde resultaat.

Zoals hieronder aangegeven, kun je een meer gedetailleerde uitleg vinden in dit andere antwoord.


Antwoord 2, autoriteit 73%

Uitvoer van subprocess.call()mag alleen worden omgeleid naar bestanden.

U moet in plaats daarvan subprocess.Popen()gebruiken. Vervolgens kunt u subprocess.PIPEdoorgeven voor de parameters stderr, stdout en/of stdin en uit de pipes lezen met behulp van de methode communicate():

from subprocess import Popen, PIPE
p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode

De redenering is dat het bestandsachtige object dat wordt gebruikt door subprocess.call()een echte bestandsdescriptor moet hebben, en dus de fileno()-methode moet implementeren. Het gebruik van een willekeurig bestand-achtig object is niet voldoende.

Zie hiervoor meer informatie.


Antwoord 3, autoriteit 28%

Voor python 3.5+ wordt aanbevolen de run-functie van de subprocess-module te gebruiken. Dit retourneert een CompletedProcess-object, waaruit u gemakkelijk zowel de uitvoer als de retourcode kunt verkrijgen.

from subprocess import PIPE, run
command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)

Antwoord 4, autoriteit 17%

Ik heb de volgende oplossing. Het legt de afsluitcode, de stdout en ook de stderr van het uitgevoerde externe commando vast:

import shlex
from subprocess import Popen, PIPE
def get_exitcode_stdout_stderr(cmd):
    """
    Execute the external command and get its exitcode, stdout and stderr.
    """
    args = shlex.split(cmd)
    proc = Popen(args, stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    exitcode = proc.returncode
    #
    return exitcode, out, err
cmd = "..."  # arbitrary external command, e.g. "python mytest.py"
exitcode, out, err = get_exitcode_stdout_stderr(cmd)

Ik heb er ook een blogbericht over hier.

Bewerken:de oplossing is geüpdatet naar een nieuwere oplossing die niet naar temp. bestanden.


Antwoord 5, autoriteit 10%

Ik heb onlangs ontdekt hoe ik dit moet doen, en hier is een voorbeeldcode van een huidig ​​project van mij:

#Getting the random picture.
#First find all pictures:
import shlex, subprocess
cmd = 'find ../Pictures/ -regex ".*\(JPG\|NEF\|jpg\)" '
#cmd = raw_input("shell:")
args = shlex.split(cmd)
output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate()
#Another way to get output
#output = subprocess.Popen(args,stdout = subprocess.PIPE).stdout
ber = raw_input("search complete, display results?")
print output
#... and on to the selection process ...

Je hebt nu de uitvoer van het commando opgeslagen in de variabele “output”. “stdout = subprocess.PIPE” vertelt de klasse om een ​​bestandsobject met de naam ‘stdout’ te maken vanuit Popen. De methode communiceer() is, voor zover ik weet, gewoon een handige manier om een ​​tupel van de uitvoer en de fouten van het proces dat je hebt uitgevoerd te retourneren. Het proces wordt ook uitgevoerd bij het instantiëren van Popen.


Antwoord 6, autoriteit 8%

De sleutel is om de functie subprocess.check_output

te gebruiken

De volgende functie legt bijvoorbeeld stdout en stderr van het proces vast en geeft dat terug, evenals of de aanroep al dan niet is geslaagd. Het is compatibel met Python 2 en 3:

from subprocess import check_output, CalledProcessError, STDOUT
def system_call(command):
    """ 
    params:
        command: list of strings, ex. `["ls", "-l"]`
    returns: output, success
    """
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success
output, success = system_call(["ls", "-l"])

Als je commando’s wilt doorgeven als strings in plaats van arrays, gebruik dan deze versie:

from subprocess import check_output, CalledProcessError, STDOUT
import shlex
def system_call(command):
    """ 
    params:
        command: string, ex. `"ls -l"`
    returns: output, success
    """
    command = shlex.split(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success
output, success = system_call("ls -l")

Antwoord 7, autoriteit 5%

In Ipython-shell:

In [8]: import subprocess
In [9]: s=subprocess.check_output(["echo", "Hello World!"])
In [10]: s
Out[10]: 'Hello World!\n'

Gebaseerd op het antwoord van sargue. Met dank aan sargue.

Other episodes