shijie xu
shijie xu

Reputation: 2097

Python Popen shell script but fail

I want to execute bash command

 '/bin/echo </verbosegc> >> /tmp/jruby.log'

in python using Popen. The code does not raise any exception, but none change is made on the jruby.log after execution. The python code is shown below.

>>> command='/bin/echo </verbosegc> >> '+fullpath
>>> command
'/bin/echo </verbosegc> >> /tmp/jruby.log'
>>process = subprocess.Popen(command.split(),  stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
>>> output= process.communicate()[0]
>>> output
'</verbosegc> >> /tmp/jruby.log\n

I also print out the process.pid and then check the pid using ps -ef | grep pid. The result shows that the process pid has been finished.

Upvotes: 1

Views: 666

Answers (4)

beroe
beroe

Reputation: 12326

Have you tried without splitting the command and using shell=True? My usual format is:

 process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
 output = process.stdout.read()       # or .readlines()

Upvotes: -1

Charles Duffy
Charles Duffy

Reputation: 295766

Consider the following:

command = [ 'printf "%s\n" "$1" >>"$2"',  # shell script to execute
            '',                           # $0 in shell
            '</verbosegc>',               # $1
            '/tmp/jruby.log' ]            # $2
subprocess.Popen(command, shell=True)

The first argument is a shell script referring to $1 and $2, which are in turn passed as separate arguments. Keeping data separate from code, rather than trying to substitute the former into the latter, is a precaution against shell injection (think of this as an analog to SQL injection).


Of course, don't actually do anything like this in Python -- the native primitives for file IO are far more appropriate.

Upvotes: 1

Padraic Cunningham
Padraic Cunningham

Reputation: 180512

Just use pass file object if you want to append the output to a file, you cannot redirect to a file unless you set shell=True:

command = ['/bin/echo', '</verbosegc>']

with open('/tmp/jruby.log',"a") as f:
     subprocess.check_call(command, stdout=f,stderr=subprocess.STDOUT)

Upvotes: 2

Tim Pierce
Tim Pierce

Reputation: 5664

The first argument to subprocess.Popen is the array ['/bin/echo', '</verbosegc>', '>>', '/tmp/jruby.log']. When the first argument to subprocess.Popen is an array, it does not launch a shell to run the command, and the shell is what's responsible for interpreting >> /tmp/jruby.log to mean "write output to jruby.log".

In order to make the >> redirection work in this command, you'll need to pass command directly to subprocess.Popen() without splitting it into a list. You'll also need to quote the first argument (or else the shell will interpret the "<" and ">" characters in ways you don't want):

command = '/bin/echo "</verbosegc>" >> /tmp/jruby.log'
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)

Upvotes: 1

Related Questions