embedding short python scripts inside a bash script

PythonBash

Python Problem Overview


I'd like to embed the text of short python scripts inside of a bash script, for use in say, my .bash_profile. What's the best way to go about doing such a thing?

The solution I have so far is to call the python interpreter with the -c option, and tell the interpreter to exec whatever it reads from stdin. From there, I can build simple tools like the following, allowing me to process text for use in my interactive prompt:

function pyexec() {
    echo "$(/usr/bin/python -c 'import sys; exec sys.stdin.read()')"
}

function traildirs() {
    pyexec <<END
trail=int('${1:-3}')
import os
home = os.path.abspath(os.environ['HOME'])
cwd = os.environ['PWD']
if cwd.startswith(home):
    cwd = cwd.replace(home, '~', 1)
parts = cwd.split('/')
joined = os.path.join(*parts[-trail:])
if len(parts) <= trail and not joined.startswith('~'):
    joined = '/'+joined
print joined
END
}

export PS1="\h [\$(traildirs 2)] % "

This approach smells slightly funny to me though, and I'm wondering what alternatives to doing it this way might be.

My bash scripting skills are pretty rudimentary, so I'm particularly interested to hear if I'm doing something silly from the bash interpreter's perspective.

Python Solutions


Solution 1 - Python

Why should you need to use -c? This works for me:

python << END
... code ...
END

without needing anything extra.

Solution 2 - Python

The python interpreter accepts - on the command line as a synonym for stdin so you can replace the calls to pyexec with:

python - <<END

See command line reference here.

Solution 3 - Python

One problem with using bash here document is that the script is then passed to Python on stdin, so if you want to use the Python script as a filter, it becomes unwieldy. One alternative is to use the bash's process substitution, something like this:

... | python <( echo '
code here
' ) | ...

If the script it too long, you could also use here document inside the paren, like this:

... | python <(
cat << "END"
code here
END
 ) | ...

Inside the script, you can read/write as you normally would from/to standard i/o (e.g., sys.stdin.readlines to gobble up all the input).

Also, python -c can be used as mentioned in other answers, but here is how I like to do it to format nicely, while still respecting Python's indentation rules (credits):

read -r -d '' script <<-"EOF"
	code goes here prefixed by hard tab
EOF
python -c "$script"

Just make sure that the first character of each line inside here document is a hard tab. If you have to put this inside a function, then I use the below trick that I saw somewhere to make it look aligned:

function somefunc() {
    read -r -d '' script <<-"----EOF"
    	code goes here prefixed by hard tab
----EOF
    python -c "$script"
}

Solution 4 - Python

Sometimes it is not a good idea to use here document. Another alternative is to use python -c:

py_script="
import xml.etree.cElementTree as ET,sys
...
"

python -c "$py_script" arg1 arg2 ...

Solution 5 - Python

If you need to use the output of the python in the bash script you can do something like this:

#!/bin/bash

ASDF="it didn't work"

ASDF=`python <<END
ASDF = 'it worked'
print ASDF
END`

echo $ASDF

Solution 6 - Python

Ready to copy-paste example with input:

input="hello"
output=`python <<END
print "$input world";
END`

echo $output

Solution 7 - Python

Interesting... I want an answer now too ;-)

He is not asking how to execute python code within a bash script but actually have the python set environment variables.

Put this in a bash script and try to get it to say "it worked".

export ASDF="it didn't work"

python <<END
import os
os.environ['ASDF'] = 'it worked'
END

echo $ASDF

The problem is that the python gets executed in a copy of the environment. Any changes to that environment aren't seen after python exits.

If there is a solution for this, I'd love to see it too.

Solution 8 - Python

Try this :

#!/bin/bash
a="test"
python -c "print  '$a this is a test'.title()"

Solution 9 - Python

If you are using zsh you can embed Python inside the script using zsh's join and python stdin option (python -):

py_cmd=${(j:\n:)"${(f)$(
    # You can also add comments, as long as you balance quotes
    <<<'if var == "quoted text":'
    <<<'  print "great!"')}"}

catch_output=$(echo $py_cmd | python -)

You can indent the Python snippet, so it looks nicer than the EOF or <<END solutions when inside functions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt AndersonView Question on Stackoverflow
Solution 1 - PythonRicardo CárdenesView Answer on Stackoverflow
Solution 2 - PythonNed DeilyView Answer on Stackoverflow
Solution 3 - PythonharidsvView Answer on Stackoverflow
Solution 4 - PythonDon LiView Answer on Stackoverflow
Solution 5 - PythondesguaView Answer on Stackoverflow
Solution 6 - PythonAdrian LopezView Answer on Stackoverflow
Solution 7 - Pythoneric.frederichView Answer on Stackoverflow
Solution 8 - Pythonuser8189586View Answer on Stackoverflow
Solution 9 - PythonfedeDevView Answer on Stackoverflow