Home > other >  How to pass bash shell variable to python?
How to pass bash shell variable to python?

Time:07-03

I read a lot of examples with same problem but I didn't solve it. I have a small python app that runs some bash commands. Most of lines are bash shell commands. App has some bash shell variables that I need them to pass outside from bash shell to python part file. I want end variable to pass outside of part bash shell.

How can I do that?

I am sorry for my English, I am not native speaker.

#!/usr/bin/python3
import os
import sys
import subprocess

if len(sys.argv) > 1:
    n = sys.argv[1]

def capture():
    subprocess.run(['/bin/bash', '-c', bash, n], check=True)

## ----STARTING BASH SHELL----

bash = '''
#!/usr/bin/env bash


INTERVAL="1"  # update interval in seconds

n=''' n '''

# How many time script will work.
start=1
end=1800 # put the number for minues. 3600 is 1 hour.


while [[ $start -le $end ]]
do
.....
.....
.....
 echo $start "Seconds" 'of' $end "Seconds until end"

'''
## ----END OF BASH SHELL


capture()

#end variable above from bash shell part I need put here.

CodePudding user response:

Try this:

#!/usr/bin/env python3
import os
import sys
import subprocess


def get_n() -> str:
    if len(sys.argv) > 1:
        n = sys.argv[1]
    else:
        n = input('Please input `n`: ')
    return n


## ----STARTING BASH SHELL----

BASH = '''
#!/usr/bin/env bash


INTERVAL="1"  # update interval in seconds

n={}

# How many time script will work.
start=1
end=1800 # put the number for minues. 3600 is 1 hour.


while [[ $start -le $end ]]
do
.....
.....
.....
 echo $start "Seconds" 'of' $end "Seconds until end"

'''
## ----END OF BASH SHELL

def capture(n, bash=BASH) -> str:
    return subprocess.run(['/bin/bash', '-c', bash.format(repr(n))], check=True, capture_output=True).stdout

def main():
    ret = capture(get_n())
    print('Output of bash result:\n' ret)

if __name__ == '__main__':
    main()

CodePudding user response:

If you want to pass values into a script that you execute, you have the following options:

  • Command-line parameters
  • environment variables
  • stdin
  • file or some other method

Let's look at each in turn...

Command-line parameters

You call your script with command-line parameters like this:

./SomeScript a "another param"

or, if the caller is Python:

sp = subprocess.run(["./SomeScript", "a", "another param"])

Then, inside the called script, you access the parameters like this:

#!/bin/bash
param1="$1"
param2="$2"
echo "First param: $param1, second param: $param2"

Or, if the called script is Python:

import sys
print(sys.argv[1:])

Environment variables

You set an environment variable before starting the script, using either of these methods:

export name="Simon"
./SomeScript

or:

name="Simon" ./SomeScript

or, if the caller is Python:

import os
os.environ['name'] = 'Simon'

Then, inside the script, you can access $name:

#!/bin/bash
echo "name is $name"

or, if the called script is Python:

import os
print(os.environ['name'])

via stdin

You send some value to the script on its stdin using one of these methods:

printf "Simon" | ./SomeScript

or, using a bash "here-string":

./SomeScript <<< "Simon"

Then, inside your script, you read the value from stdin into a variable with:

#!/bin/bash

read -r name

Or, if the called script is Python:

#!/usr/bin/env python3
v = input()
print(f'Read from stdin: {v}')

Note that you could equally read from sys.stdin or other methods.

via file or some other method

Other ways of passing values into scripts include letting them read from a disk file, or a database, or Redis, or a socket, or a message queue...

Here's an example with Redis which lets you share strings, atomic integers, hashes, lists, queues, images, sets and other data structures between different processes - even in different machines. First, one script puts a value into Redis:

redis-cli set name "Simon"

then any other process (whether bash, Python, PHP, Rust) on any machine, can retrieve the value with:

redis-cli get name

If you want to access the output from a script you called, you have the following options:

  • printed result
  • exit status
  • text file, or database, or other app

Let's look at each in turn.

printed result

The script prints something on its stdout, or stderr like this:

#!/bin/bash
printf "Some result"
>&2 printf "Some error"

And the caller, if bash can pick it up like this:

#!/bin/bash
result=$( ./SomeScript )

Or, if the caller is Python, it can catch the output from subprocess.run().

sp = subprocess.run(["./SomeScript"], capture_output=True)
print(sp.stdout, sp.stderr)

exit status - mostly just for true/false outputs

The script exits with an exit status like this:

#!/bin/bash
exit 3

And the caller, if bash can pick it up like this:

#!/bin/bash
./SomeScript
status=$?

Or, if the caller is Python, it can catch the exit status from subprocess.run().

sp = subprocess.run(["./SomeScript"], capture_output=True)
print(sp.returncode)

file output

As before, the called script can write to a file on disk, or a database, or a socket, or a message queue, or Redis as above.

  • Related