Created
April 27, 2018 16:53
-
-
Save Jwink3101/728605b43ca55f7d3be16d810b16af9b to your computer and use it in GitHub Desktop.
Two examples of running python inside a bash script. The first is a simple one that just returns a result while the second gives bash a series of commands to run or a result to print (such as from parsing command line arguments).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
############################################################################ | |
################################## Intro ################################### | |
############################################################################ | |
# Example on how to run python inside of bash. Anything that is printed | |
# in the python part is "returned" to bash | |
# | |
# Examples: | |
# Simple: Just return the output | |
# Complex: Tell bash which commands to run and/or print results from | |
# parsing the command-line arguments | |
# | |
# Why: | |
# This is useful when you want to be able to 'source script.sh' and/or | |
# when you need to be able to use certain environment variables and paths | |
# such as bash environment modules. | |
# | |
# For many uses, python subprocess is a *MUCH* better solution | |
# | |
# Gotchas: | |
# There are a few things to know about writing these combined scripts: | |
# * Bash variables will be expanded! This can be useful, but may | |
# also cause problems | |
# * Certain characters, even when in python string, must be escped or | |
# avoided. The most notable example is the backtick "`" | |
# * sys.argv in python is what is passed! Not the one for the script. | |
# See the second invocation for "Simple Example" | |
############################################################################ | |
############################## Simple Example ############################## | |
############################################################################ | |
# This example is just to do some minor processing. | |
adder(){ | |
python - "$@" <<ENDPY | |
import sys | |
tot = 0.0 | |
for arg in sys.argv[1:]: | |
tot = tot + float(arg) | |
# return | |
print(tot) | |
ENDPY | |
} | |
# These are commented out for the complex example below. | |
#echo $(adder 1 2 3.4) # Add specific arguments | |
#echo $(adder "$@") # Add the arguments from the command line | |
############################################################################ | |
############################# Complex Example ############################## | |
############################################################################ | |
# This example demonstrates some more advanced usage. This is, of course, a | |
# toy problem but it demonstrates how to use python do build a complex | |
# command. As noted in the Intro, this is useful when you want to execute | |
# a series of bash commands in the primary bash environment (and potentially | |
# with a "source myscript.sh" invocation) | |
# Remember that variables are filled in | |
VERSION='20180427' | |
PROG='adder-example' | |
# This is used as a sentinel to later execute vs just echo. This is NOT the | |
# main example | |
execflag=$(python -c "import random;print(''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(50)))") | |
adder_cli() { | |
python - "$@" <<ENDPY | |
from __future__ import division, print_function, unicode_literals | |
__version__ = $VERSION | |
import sys | |
import argparse | |
sys.argv[0] = "$PROG" # Force the name | |
description=""" | |
Add (or subtract if set) command line arguments. Print them to the screen | |
and then *also* write to a file. (recall this is a toy example) | |
""" | |
parser = argparse.ArgumentParser(description=description,epilog='version: $VERSION') | |
parser.add_argument('--neg',action='store_true',help='Negate the sum') | |
parser.add_argument('num',nargs='+',help='number to add') | |
args = parser.parse_args(sys.argv[1:]) | |
# Send in the execflag so everything else gets evaluated by bash | |
print('${execflag}') | |
tot = sum(float(a) for a in args.num) | |
if args.neg: tot = -1.0*tot | |
bashcmd = [] | |
bashcmd.append('echo "The sum in: {}"'.format(tot)) | |
bashcmd.append('echo "The sum in: {}" >> exampleout'.format(tot)) | |
for cmd in bashcmd: | |
print(cmd) | |
ENDPY | |
} | |
# This part calls the python code and then either executes it or | |
# just prints the result | |
cmd=$(adder_cli "$@") | |
if [[ "$cmd" == ${execflag}* ]]; then | |
# Means we run it | |
IFS= # Makes it not break at new lines | |
cmd="$(echo $cmd | sed "s/${execflag}//g")" | |
IFS=$'\n' | |
for line in $cmd; do | |
echo "[$PROG] executing: \$ ${line}" | |
eval "$line" | |
done | |
else | |
echo "$cmd" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment