简体   繁体   中英

How to pass bash shell variable to python?

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 start and end variables to pass outside of part bash shell. I have to say that I write python3 count.py enp35s0 to run my python app.

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
import time

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

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


bash = '''
#!/usr/bin/env bash
#set -x

INTERVAL="1"  # update interval in seconds

n='''+n+'''

# How many time script will work.
start=1
end=2 # put the number for minues. 3600 is 1 hour.
#end=$(( 1 * 2700 ))

while [[ $start -le $end ]]
do
    #echo "$start"
    ((start = start + 1))

    # Capture packets.
    R1=`cat /sys/class/net/$n/statistics/rx_bytes`
    T1=`cat /sys/class/net/$n/statistics/tx_bytes`
    sleep $INTERVAL
    R2=`cat /sys/class/net/$n/statistics/rx_bytes`
    T2=`cat /sys/class/net/$n/statistics/tx_bytes`
    TBPS=`expr $T2 - $T1`
    RBPS=`expr $R2 - $R1`
    TKBPS=`expr $TBPS / 1024`
    RKBPS=`expr $RBPS / 1024`
    echo "TX $1: $TKBPS kB/s RX $1: $RKBPS kB/s"

    # Sum number of packets sent and received on an interface
    SUM=$(expr $RKBPS)

    # If there is internet traffic, reset count to zero.
    if (( $SUM >= 10 ));then
        ((i = 0))
        echo "Connection is active:"
    fi

    now=$(( $SUM ))
    max=$((sum>max?sum:max))
    if [ $now -gt $max ] ; then
        max=$now
    fi

    wget -q --spider http://example.com
    if [ $? -eq 0 ]; then
        echo "Online"
        ((no_internet = 0 ))
    else
#       echo "Offline"
        no_internet=$(( no_internet+1 ))
    fi

    if [ $no_internet -gt 10 ] ; then
        echo "off"
        /sbin/shutdown -h now
    fi


echo "The SUM is: $SUM"
echo "The maximum download bandwidth is: $max"
#echo
echo $start "Seconds" 'of' $end "Seconds until end"

done
# When script reach here then will shutdown the system.
/sbin/shutdown -h now

'''
capture()

#-----HERE I WANT TO PUT 2 VARIABLES

#start variable
start= #----result from bash shell script above

#end variable 
end= #----result from bash shell script above

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(bash.format(repr(n)), shell=True, check=True, capture_output=True).stdout.strip().decode()

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

if __name__ == '__main__':
    main()

Updated Answer

Here's a bash script called script.sh that accepts 2 parameters and outputs each parameter doubled:

#!/bin/bash
p1=$1
p2=$2
((result1=p1*2))
((result2=p2*2))
echo "${result1} ${result2}"

Now call it from Python and get the results:

import subprocess 
sp = subprocess.run(["./script.sh","1","5"], capture_output=True)
result1, result2 = sp.stdout.split()
print(result1, result2)   # prints 2, 10

Original Answer

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM