20

So I'm trying to move away from os.popen to subprocess.popen as recommended by the user guide. The only trouble I'm having is I can't seem to find a way of making readlines() work.

So I used to be able to do

list = os.popen('ls -l').readlines()

But I can't do

list = subprocess.Popen(['ls','-l']).readlines()
rypel
  • 4,686
  • 2
  • 25
  • 36
joedborg
  • 17,651
  • 32
  • 84
  • 118
  • 1
    would rather do `list = subprocess.call(['ls','-l']).readlines() ` – joedborg Sep 19 '11 at 09:14
  • 2
    That's wrong -- `call` only returns the returncode, not the output. – agf Sep 19 '11 at 09:18
  • http://stackoverflow.com/questions/2924310/whats-a-good-equivalent-to-pythons-subprocess-check-call-that-returns-the-conte – jfs Sep 19 '11 at 09:53

5 Answers5

39
ls = subprocess.Popen(['ls','-l'], stdout=subprocess.PIPE)
out = ls.stdout.readlines()

or, if you want to read line-by-line (maybe the other process is more intensive than ls):

for ln in ls.stdout:
    # whatever
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • 7
    This approach is preferable to the accepted answer as it allows one to read through the output as the sub process produces it. – Rob Marrowstone Jul 21 '16 at 23:19
  • You need to iterate differently over `stdout`. – Mad Physicist Nov 18 '22 at 03:46
  • **Don't do that**, the Python3 documentation states the following: "Warning: Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process. " – ShellCode Jul 23 '23 at 17:28
32

With subprocess.Popen, use communicate to read and write data:

out, err = subprocess.Popen(['ls','-l'], stdout=subprocess.PIPE).communicate() 

Then you can always split the string from the processes' stdout with splitlines().

out = out.splitlines()
agf
  • 171,228
  • 44
  • 289
  • 238
  • Thought this was meant to be the "nice new way" of doing it. Thanks for the answer, I'll set it when the timeout reaches. I mihg tjust stick to popen. – joedborg Sep 19 '11 at 09:25
  • 4
    The problem with `communicate` is that you get all of the output at once, which in the case of a non-recursive `ls` is not likely a problem. By using the `stdout` member, you can read line-by-line (think `find`). – Fred Foo Sep 19 '11 at 09:33
  • @FredFoo That's right... I've created a little thread [here](https://stackoverflow.com/questions/60858329/custom-popen-communicate-method-gives-wrong-output) in order to try to address what you're mentioning in your comment... it's not working well yet though :) – BPL Mar 26 '20 at 00:43
13

Making a system call that returns the stdout output as a string:

lines = subprocess.check_output(['ls', '-l']).splitlines()
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Nice, I guess it's not widely known because it's Python 2.7+ only. – agf Sep 19 '11 at 10:04
  • @agf: follow the link there is an adaption for older Python versions. – jfs Sep 19 '11 at 10:10
  • I know, I already followed both links you posted (and upvoted each post). I was just surprised that I didn't know about this convenience function until I saw it was 2.7+. – agf Sep 19 '11 at 10:15
  • This one is the recommended solution, if you are using 2.7+ – tbrittoborges Nov 19 '15 at 11:55
3
list = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0].splitlines()

straight from the help(subprocess)

Kimvais
  • 38,306
  • 16
  • 108
  • 142
3

A more detailed way of using subprocess.

# Set the command
command = "ls -l"

# Setup the module object
proc = subprocess.Popen(command,
                    shell=True,   
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE)

# Communicate the command   
stdout_value,stderr_value = proc.communicate()

# Once you have a valid response, split the return output    
if stdout_value:
    stdout_value = stdout_value.split()
Neuron
  • 5,141
  • 5
  • 38
  • 59
thirumalaa srinivas
  • 3,530
  • 1
  • 16
  • 5