7

I have a bash script that calls a python script. At first I was just returning one variable and that is fine, but now I was told to return two variables and I was wondering if there is a clean and simple way to return more than one variable.

archiveID=$(python glacier_upload.py $archive_file_name $CURRENTVAULT)

Is the call I make from bash

print archive_id['ArchiveId']
archive_id['ArchiveId']

This returns the archive id to the bash script

Normally I know you can use a return statement in python to return multiple variables, but with it just being a script that is the way I found to return a variable. I could make it a function that gets called but even then, how would I receive the multiple variables that I would be passing back?

2 Answers 2

11

The safest and cleanest way to parse any input effectively in bash is to map into an array,

mapfile -t -d, <<<"$(python your_script.py)"

Now you just need to make sure you script outputs the data you want to read with the chosen delimiter, "," in my example (-d selects a delimiter, -t trims input like newlines). The quotes are non-optional to ensure the shell doesn't separate things with spaces.

If you have a tuple of things that do not contain commas, this would be enough:

print(str(your_tuple).strip('()'))

Below some easy ways for easy input, before I was more familiar with Bash:

My favorite way is reading straight into a list:

x=($(python3 -c "print('a','b','c')"))
echo ${x[1]}
b
echo ${x[*]}
a b c

for this reason if my_python_function returns a tuple, I would use format to make sure I just get space delimited results:

#Assuming a tuple of length 3 is returned
#Remember to quote in case of a space in a single parameter!
print('"{}" "{}" "{}"'.format(*my_python_function())

If you want this to be generic you would need to construct the format string:

res = my_python_function()
print(("{} "*len(res)).format(*res))

is one way. No need to worry about the extra space, but you could [:-1] on the format string to get rid of it.

Finally, if you are expecting multi-word arguments (i.e. a space in a single argument, you need to add quotes, and a level of indirection (I am assuming you will only be running your own, "safe", scripts):

#myfile.py
res = my_python_function()
print(('"{}" '*len(res)).format(*res))

#my file.bash
eval x=($(python3 myfile.py))
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for sharing another way :)
10

From your python script, output one variable per line. Then from you bash script, read one variable per line:

Python

print "foo bar"
print 5

Bash

#! /bin/bash

python main.py | while read line ; do
    echo $line
done

Final Solution:

Thanks Guillaume! You gave me a great starting point out the soultion. I am just going to post my solution here for others.

#! /bin/bash

array=()
while read line ; do
  array+=($line)
done < <(python main.py)
echo ${array[@]}

I found the rest of the solution that I needed here

1 Comment

You could also say mapfile -t array < <(python main.py) -- see help mapfile from a bash prompt.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.