2

I want to run this command using call subprocess

ls -l folder | wc -l

My code in Python file is here:

subprocess.call(["ls","-l","folder","|","wc","-l"])

I got an error message like this:

ls: cannot access |: No such file or directory
ls: cannot access wc: No such file or directory

It's like command |wc can't be read by call subprocess.

How can i fix it?

Diogo Rocha
  • 9,759
  • 4
  • 48
  • 52
Rembulan Moon
  • 338
  • 3
  • 11
  • Pipes are shell thing. The shell would fork two subprocess, and pipe stdout of 1st subprocess into stdin of 2nd one. You would need to implement that logic yourself. – Jazzwave06 Feb 13 '16 at 03:18

4 Answers4

4

Try out the shell option using a string as first parameter:

subprocess.call("ls -l folder | wc -l",shell=True)

Although this work, note that using shell=True is not recommended since it can introduce a security issue through shell injection.

Arton Dorneles
  • 1,629
  • 14
  • 18
  • Thank you its working well :) – Rembulan Moon Feb 13 '16 at 03:26
  • It's not returning expected result, it's just that error has gone – AlokThakur Feb 13 '16 at 03:28
  • Thank you AlokThakur. The first parameter must be a string. Should be working now. – Arton Dorneles Feb 13 '16 at 03:42
  • Hi @Rembulan if this or any answer has solved your question please consider [accepting it](http://meta.stackexchange.com/q/5234/179419) by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this. – Arton Dorneles Feb 21 '16 at 14:20
1

You can setup a command pipeline by connecting one process's stdout with another's stdin. In your example, errors and the final output are written to the screen, so I didn't try to redirect them. This is generally preferable to something like communicate because instead of waiting for one program to complete before starting another (and encouring the expense of moving the data into the parent) they run in parallel.

import subprocess

p1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["wc","-l"], stdin=p1.stdout)
# close pipe in parent, its still open in children
p1.stdout.close()
p2.wait()
p1.wait()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

You'll need to implement the piping logic yourself to make it work properly.

def piped_call(prog1, prog2):
  out, err = subprocess.call(prog1).communicate()
  if err:
    print(err)
    return None
  else:
    return subprocess.call(prog2).communicate(out)
0

You could try using subprocess.PIPE, assuming you wanted to avoid using subprocess.call(..., shell=True).

import subprocess

# Run 'ls', sending output to a PIPE (shell equiv.: ls -l | ... )
ls = subprocess.Popen('ls -l folder'.split(),
                      stdout=subprocess.PIPE)

# Read output from 'ls' as input to 'wc' (shell equiv.: ... | wc -l)
wc = subprocess.Popen('wc -l'.split(), 
                      stdin=ls.stdout, 
                      stdout=subprocess.PIPE)

# Trap stdout and stderr from 'wc'
out, err = wc.communicate()

if err:
    print(err.strip())

if out:
    print(out.strip())

For Python 3 keep in mind the communicate() method used here will return a byte object instead of a string. :

In this case you will need to convert the output to a string using decode():

if err:
    print(err.strip().decode())
if out:
    print(out.strip().decode())
Joe
  • 99
  • 4