7

I have written a Python module which contains functions that return arrays. I want to be able to access the string arrays returned from the python module, and iterate over in a bash script, so I may iterate over the array elements.

For example:

Python module (mymod)

def foo():
    return ('String', 'Tuple', 'From', 'Python' )

def foo1(numargs):
    return [x for x in range(numargs)]

Bash script

foo_array  = .... # obtain array from mymod.foo()
for i in "${foo_array[@]}"
do
    echo $i
done


foo1_array = .... # obtain array from mymod.foo1(pass arg count from bash)
for j in "${foo1_array[@]}"
do
    echo $j
done

How can I implement this in bash?.

version Info:

Python 2.6.5 bash: 4.1.5

Homunculus Reticulli
  • 65,167
  • 81
  • 216
  • 341

5 Answers5

14

Second try - this time shell takes the integration brunt.

Given foo.py containing this:

def foo():
        foo = ('String', 'Tuple', 'From', 'Python' )
        return foo

Then write your bash script as follows:

#!/bin/bash
FOO=`python -c 'from foo import *; print " ".join(foo())'`
for x in $FOO:
do
        echo "This is foo.sh: $x"
done

The remainder is first answer that drives integration from the Python end.

Python

import os
import subprocess

foo = ('String', 'Tuple', 'From', 'Python' )

os.putenv('FOO', ' '.join(foo))

subprocess.call('./foo.sh')

bash

#!/bin/bash
for x in $FOO
do
        echo "This is foo.sh: $x"
done
Maria Zverina
  • 10,863
  • 3
  • 44
  • 61
  • Thanks for the feedback. I want my Python module to be agnostic of who/what is calling it (separation of concerns) - the code you suggested requires modifying the python code - which is not ideal. – Homunculus Reticulli Jul 09 '12 at 09:26
  • @HomunculusReticulli OK - hope I understood it right now - the new code uses shell to drive the integration. – Maria Zverina Jul 09 '12 at 09:33
  • YES! - that intuitively makes sense!. Thanks very much!. Just tried it and it works :) – Homunculus Reticulli Jul 09 '12 at 10:14
  • BTW, I am guessing that to pass a value from bash to Python, I generate the string in bash and use the -c option to pass from bash->python?. To pass compound data types (e.g. array), I probably need to write a wrapper function at the python end to parse in the passed value(s) - is my assumption correct, or is there a better way to pass data from bash -> python function? – Homunculus Reticulli Jul 09 '12 at 10:19
  • @HomunculusReticulli Your suggestion will work - you can also pass it via environment variable like this `python -c "import os; print os.getenv('HOME')"` – Maria Zverina Jul 09 '12 at 10:25
1

In addition, you can tell python process to read STDIN with "-" as in

echo "print 'test'" | python -

Now you can define multiline snippets of python code and pass them into subshell

FOO=$( python - <<PYTHON

def foo():
    return ('String', 'Tuple', 'From', 'Python')

print ' '.join(foo())

PYTHON
)

for x in $FOO
do
    echo "$x"
done

You can also use env and set to list/pass environment and local variables from bash to python (into ".." strings).

Community
  • 1
  • 1
Yauhen Yakimovich
  • 13,635
  • 8
  • 60
  • 67
0

In lieu of something like object serialization, perhaps one way is to print a list of comma separated values and pipe them from the command line.

Then you can do something like:

> python script.py | sh shellscript.sh
Husman
  • 6,819
  • 9
  • 29
  • 47
0

This helps too. script.py:

 a = ['String','Tuple','From','Python']

    for i in range(len(a)):

            print(a[i])

and then we make the following bash script pyth.sh

#!/bin/bash

python script.py > tempfile.txt
readarray a < tempfile.txt
rm tempfile.txt

for j in "${a[@]}"
do 
      echo $j
done

sh pyth.sh

0

As well as Maria's method to obtain output from python, you can use the argparse library to input variables to python scripts from bash; there are tutorials and further docs here for python 3 and here for python 2.

An example python script command_line.py:

import argparse
import numpy as np

if __name__ == "__main__":

    parser = argparse.ArgumentParser()

    parser.add_argument('x', type=int)

    parser.add_argument('array')

    args = parser.parse_args()

    print(type(args.x))
    print(type(args.array))
    print(2 * args.x)

    str_array = args.array.split(',')
    print(args.x * np.array(str_array, dtype=int))

Then, from a terminal:

$ python3 command_line.py 2 0,1,2,3,4
# Output
<class 'int'>
<class 'str'>
4
[0 2 4 6 8]
Dagorodir
  • 104
  • 1
  • 10