1

After years of bash scripting I've been given the task of modifying a python script to have it call a shell script when certain conditions are met. That part wasn't too bad, but now I'm trying to also send this shell script a variable from within the python script and I'm getting lost.

The shell script takes stdin, which is where I'm trying to place the value of the python variable, which is just an interger.

my code (so far) looks like this:

if VAR > NUMBER:
import os
bashCommand = "echo something | /path/to/script --args"
os.system(bashCommand) 

and it works just fine. But what I am looking to do is make os.system(bashCommand) an equivalent of:

echo $VAR | /path/to/script --args

or even

echo 'some text' $VAR | /path/to/script --args

given the way os.system appears to work though it seems I'm approaching this completely wrong.

So I guess my question is how can I pass the value of VAR to bashCommand, preferably as stdin?

1

Python doesn't expand variables in strings in the same way as bash. If you have VAR in python and want to pass that to bash you could do

subprocess.call('echo {} | /path/to/script --args'.format(VAR), shell=True)

if VAR in python holds the name of a bash variable you want to expand you could do similar:

subprocess.call('echo "${}" | /path/to/script --args'.format(VAR), shell=True)
  • I'm not sure of the best-practice/security issues of using "shell=' but this worked for me. Marking resolved. – kadamwolfe Sep 4 '15 at 14:44
4

Don't use os.system(), it is deprecated in favor of subprocess module.

In your case you can use subprocess module directly and its better to not use the shell=True parameter as this is not safe to run commands directly into the shell. All the functionalities you need here like pipe can be emulated by the subprocess module.

Lets take this example :

import subprocess
var = 'foobar'

first = subprocess.Popen(['/bin/echo', var], stdout=subprocess.PIPE)
second = subprocess.Popen(['bash', '/path/to/script', '--args'], stdin=first.stdout)

we have defined a varible var, then we have used the subprocess.Popen class to get the value of var using /bin/echo and then sent this value to the pipe. The first is an object of subprocess.Popen class.

Then we have used the STDOUT of first as STDIN of second via pipe and executed the bash script accordingly.

If you want to save the output of a command as a string use subprocess.check_output function instead e.g. :

second = subprocess.check_output(['bash', '/path/to/script', '--args'], stdin=first.stdout)

Read the offical documentation of subprocess module to get more idea.

  • This is great information and I think I could use it. The one thing I think I should mention though is that 'VAR' is a variable (integer) defined by the python script (that is to call the shell script) so we may not need to echo it, right? since python already knows its value. – kadamwolfe Sep 3 '15 at 20:00
  • @kadamwolfe Yeah..you can use it directly then as I have used in the second object generation..I was just pointing out the processes in my sample script..fit it to meet your need :) – heemayl Sep 3 '15 at 20:04
  • nice. so something like.... subprocess.Popen(['bash', '/path/to/script', '--args'], stdin="some text" VAR) ? – kadamwolfe Sep 3 '15 at 20:06
  • @kadamwolfe I probably have misunderstood your point, you can't directly use a string as STDIN as it does not have fileno attribute..you can combine the two into a simple one liner: subprocess.Popen(['bash', '/path/to/script'], stdin=subprocess.Popen(['/bin/echo', var], stdout=subprocess.PIPE).stdout) ,if its a one time run then you can consider subprocess.call instead of subprocess.Popen.. – heemayl Sep 3 '15 at 20:21
  • While I do appreciate the help, I'm not sure it resolves my issue. I'm checking if a variable's value is greater than another and if so, echo that variable's value to a shell script (preferably pre-pended by a text string. if VAR > NUMBER: <echo text string + VAR's value to /path/to/script --args> – kadamwolfe Sep 3 '15 at 20:40
0

Calling os.system() is deprecated, though still valid. That functionality may be going away in the future (probably will be), so you might want to give serious consideration to refactoring those calls with the subprocess module, which has an very easy way to send data to a subprocess's STDIN and read from its STDOUT. https://docs.python.org/2/library/subprocess.html

0

I think the good practice is:

var = subprocess.Popen(['/bin/echo', var], stdout=subprocess.PIPE)
second = subprocess.Popen(['bash', '/path/to/script', '--args'],stdin=var.stdout, stdout=subprocess.PIPE)
var.stdout.close()
output = second.communicate()[0]
var.wait()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.