19

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,392
  • 2
  • 23
  • 36
joedborg
  • 16,427
  • 30
  • 80
  • 114
  • 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
  • 342,876
  • 71
  • 713
  • 819
  • 7
    This approach is preferable to the accepted answer as it allows one to read through the output as the sub process produces it. – Hoons Jul 21 '16 at 23:19
31

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
  • 160,324
  • 40
  • 275
  • 231
  • 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
  • 374,366
  • 172
  • 933
  • 1,594
  • 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
  • 36,728
  • 16
  • 105
  • 138
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()
thirumalaa srinivas
  • 3,290
  • 1
  • 15
  • 5