16
votes

I have a bash script, a.sh , and in it I have call a python script b.py . The python script calculates something, and I want it to return a value that will be used later in a.sh . I know I can do

In a.sh:

var=`python b.py`

In b.py:

print x # when x is the value I want to pass

But this is not so convenient, because I also print other messages in b.py

Is there any better way to do it?

Edit:

What I'm doing now is just

var=`python b.py | tail -n 1`

It means I can print many things inside b.py, but only the last line (the last print command, assuming it doesn't contain "\n" in it) will be stored in var.

Thanks for all the answers!

7
Well, maybe you could not do the batch script to starty with - do everything from Python, from where the disctintion between data and code is always clear, you don't have to spawn a new proccess simply to read a scalar value (like the answers using "cat" bellow), and so on. - jsbueno

7 Answers

10
votes

I would print it to a file chosen on the command line then I'd get that value in bash with something like cat.

So you'd go:

python b.py tempfile.txt
var=`cat tempfile.txt`
rm tempfile.txt

[EDIT, another idea based on other answers]

Your other option is to format your output carefully so you can use bash functions like head/tail to pipe only the first/last lines into your next program.

4
votes

I believe the answer is

.py

import sys 
a=['zero','one','two','three'] 
b = int(sys.argv[1]) 
###your python script can still print to stderr if it likes to 
print >> sys.stderr, "I am no converting" 
result = a[b] 
print result

.sh

#!/bin/sh 

num=2 
text=`python numtotext.py $num` 
echo "$num as text is $text" 
1
votes

I'm not sure about "better", but you could write the result to a file then read it back in in Bash and delete it afterwards.

This is definitely ugly, but it's something to keep in mind in case nothing else does the trick.

1
votes

In your python script, redirect another messages to stderr, and print x to stdout:

import sys
...
print >>sys.stderr, "another message"
print x

in the bash script:

...
var=`python b.py 2>/dev/null`

Also, if x is an integer between 0,255, you can use exit code to pass it to the bash:

import sys
...
sys.exit(x)

in bash:

python b.py
var=$?

Please note that exit code is used to indicates errors, 0 means no error, and this breaks the convention.

1
votes

On bash backsticks works

I usualy do something like

PIP_PATH=`python -c "from distutils.sysconfig \
import get_python_lib; print(get_python_lib())"`


POWELINE_PATH=$PIP_PATH"/powerline"
echo $POWELINE_PATH
0
votes

You can write the output to a temporary file, and have the shell read and delete that file. This is even less convenient, but reserves stdout for communication with the user.

Alternatively, you can use some kind of format for stdout: the first n lines are certain variables, the rest will be echoed by the parent shell to the user. Also not convenient, but avoids using tempfiles.

0
votes

In shell script you can use like this python_ret=$(python b.py). It contains all print messages from python file b.py. Then you can search for a string which you are looking for. For example, if you are looking for 'Exception', you can lieke this

if [[ $python_ret == *"Exception:"* ]]; then
    echo "Got some exception."
    exit 1
fi