6

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?

asked Dec 8, 2015 at 3:15

2 Answers 2

7

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)
answered Dec 8, 2015 at 3:34
Sign up to request clarification or add additional context in comments.

Comments

7

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?

answered Dec 8, 2015 at 21:40

2 Comments

Thanks. I was aware of the Popen syntax but was specifically looking for how to chain commands with subprocess.run in Python 3.5+. And it is indeed possible to chain commands using the input argument to subprocess.run.
@ChrisClark: do you understand the difference between: ls | cowsay and output=$(ls); cowsay <<< "$output"?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.