Reputation: 2450
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?
Upvotes: 7
Views: 8948
Reputation: 25980
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))
Upvotes: 11
Reputation: 10971
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
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
Upvotes: 9