问题
I'm experimenting with subprocess.run in Python 3.5. To chain two commands together, I would have thought that the following should work:
import subprocess
ps1 = subprocess.run(['ls'], universal_newlines=True, stdout=subprocess.PIPE)
ps2 = subprocess.run(['cowsay'], stdin=ps1.stdout)
However, this fails with:
AttributeError: 'str' object has no attribute 'fileno'
ps2
was expecting a file-like object, but the output of ps1
is a simple string.
Is there a way to chain commands together with subprocess.run
?
回答1:
Turns out that subprocess.run
has an input
argument to handle this:
ps1 = subprocess.run(['ls'], universal_newlines=True, stdout=subprocess.PIPE)
ps2 = subprocess.run(['cowsay'], universal_newlines=True, input=ps1.stdout)
Also, the following works as well, which doesn't use input
:
ps1 = subprocess.run(['ls'], universal_newlines=True, stdout=subprocess.PIPE)
ps2 = subprocess.run(['cowsay', ps1.stdout], universal_newlines=True)
回答2:
subprocess.run()
can't be used to implement ls | cowsay
without the shell because it doesn't allow to run the individual commands concurrently: each subprocess.run()
call waits for the process to finish that is why it returns CompletedProcess
object (notice the word "completed" there). ps1.stdout
in your code is a string that is why you have to pass it as input
and not the stdin
parameter that expects a file/pipe (valid .fileno()
).
Either use the shell:
subprocess.run('ls | cowsay', shell=True)
Or use subprocess.Popen
, to run the child processes concurrently:
from subprocess import Popen, PIPE
cowsay = Popen('cowsay', stdin=PIPE)
ls = Popen('ls', stdout=cowsay.stdin)
cowsay.communicate()
ls.wait()
See How do I use subprocess.Popen to connect multiple processes by pipes?
来源:https://stackoverflow.com/questions/34147353/python-subprocess-chaining-commands-with-subprocess-run