How to include python script inside a bash script

I need to include below python script inside a bash script.

If the bash script end success, I need to execute the below script:

#!/usr/bin/python    
from smtplib import SMTP
import datetime
debuglevel = 0

smtp = SMTP()
smtp.set_debuglevel(debuglevel)
smtp.connect('192.168.75.1', 25)
smtp.login('my_mail', 'mail_passwd')

from_addr = "My Name <my_mail@192.168.75.1>"
to_addr = "<my_mail@192.168.75.1"
subj = "Process completed"
date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" )
#print (date)
message_text = "Hai..nnThe process completed."

msg = "From: %snTo: %snSubject: %snDate: %snn%s" % ( from_addr, to_addr, subj, date, message_text )

smtp.sendmail(from_addr, to_addr, msg)
smtp.quit()
Asked By: Amal P Ramesh

||

The simplest approach is to just save the python script as, for example script.py and then either call it from the bash script, or call it after the bash script:

#!/usr/bin/env bash
echo "This is the bash script" &&
/path/to/script.py

Or

script.sh && script.py
Answered By: JohannRamos

You can use heredoc if you want to keep the source of both bash and python scripts together. For example, say the following are the contents of a file called pyinbash.sh:

#!/bin/bash

echo "Executing a bash statement"
export bashvar=100

cat << EOF > pyscript.py
#!/usr/bin/python
import subprocess

print 'Hello python'
subprocess.call(["echo","$bashvar"])

EOF

chmod 755 pyscript.py

./pyscript.py

Now running pyinbash.sh will yield:

$ chmod 755 pyinbash.sh
$ ./pyinbash.sh
Executing a bash statement
Hello python
100
Answered By: Ketan Maheshwari

Just pass a HereDoc to python -.

From python help python -h:

- : program read from stdin

#!/bin/bash

MYSTRING="Do something in bash"
echo $MYSTRING

python - << EOF
myPyString = "Do something on python"
print myPyString

EOF

echo "Back to bash"
Answered By: Dalvenjia

How about this for an example:

PYTHON_BIN=/usr/bin/python
if [ -x $PYTHON_BIN ]; then
$PYTHON_BIN -c "print 'Hello, world'"
else
echo 'Hello, world'
fi

VS

$ ./foobar.py
env: python: No such file or directory
Answered By: echo9

This is old question, but maybe useful for someone.
It’s a way to include Python script inside a Bash script and use sys.stdin.

Extract Python script and run it with -c. The trick is to use a function, that allows use ' and " in the script. Also sys.stdin is available.

#!/bin/bash

read_file()
{
  local name="${1//./[.]}"  # escape name for sed regex
  sed -En '/^#---=== '"$name"' ===---$/,$ {/^#---=== '"$name"' ===---$/ n; /^#---===/ q; p; }' "$0"
}

echo Johny | python3 -c "$(read_file script.py)"
exit

#---=== script.py ===---
import sys
print('Your name is', sys.stdin.readline().strip())
#---===---

Explanation

Bash parse and execute a script line by line (command by command). It allows to put anything after exit, even binary data.

There is a file-system section in our case there. Line starting with #---=== are detected by the sed regular expression. The file content between the lines are printed out… and used as a script in Python with -c.

It’s possible to put many files between #---=== patterns.

Details
  1. Python execute code from a -c argument.
  2. There is shell substitution used, $() executes command and put its stdout as a text.
  3. The read_file function takes a filename as the first argument.
  4. ${//} replaces all dots in the filename and next the replaced filename is put into local variable name
  5. Dot (.) means any character in a regular expression, [] is a list od characters, than [.] means a dot literally.
  6. sed is a stream text editor, there is used:
    • -E – use extended regular expressions in the script
    • -n – suppress automatic printing of pattern space
  7. Sed operates on the same script file $0, it’s way we can use only one file.
  8. Sed takes lines by range command (PAT,PAT)
    • starting from regex /…/ (#---=== with the filename and ===---)
    • to the end of the script $
    • note: whole script command is quoted, but an apostrophe ' suppress $VAR substitution, then there are more quotations '...'"$name"'...'.
  9. Next are set of command to work on the lines range {…}, separated by semicolon ;
  10. First line from the lines range is skipped (n like next), there is #---=== FILENAME ===--- line. The same pattern is used in //.
  11. If there is another #---=== line (//) it means the next file section in the script, than the command q (lik quit) is used. This trick allows as to use end of file ($) in the line range pattern.
  12. Just print a line with command p. All printed lines are after #---=== FILENAME ===--- and before next #---===
  13. Ale printed lines from sed command are executed in the Python.
Answered By: rysson

As shown (but not explained) in a couple of other answers,
and as documented in the Python 3.11.1 documentation
Command line and environment,
you can use -c command:

-c command

    Execute the Python code in command. 
    command can be one or more statements separated by newlines,
    with significant leading whitespace as in normal module code.

In other words, you can put your entire Python script into a Bash string. 
Here’s a slightly complicated / convoluted approach,
using command substitution and a here document:

#!/bin/bash
python3 -c "$(cat << EOF

a = input('?>')
print('you typed', a)
print('33[1;32mbye...33[m')

EOF
)"            

This works. 
The $() (command substitution) passes the output of the command inside
(in this case cat) as the argument to Python. 
There is no pipelining so standard input can be used in the Python code.

This simpler approach (making the Python script a literal string)
also works:

#!/bin/bash

python3 -c "
a = input('?>') 
print('you typed', a)
print('33[1;32mbye...33[m')"

This has the usual issue with double-quoted strings in Bash:
shell meta-characters ", $, ` and  need to be escaped. 
For example, if you need to use " in your Python code,
you should escape it like this:

#!/bin/bash

python3 -c "
a = input('?>') 
print("you typed", a)
print("33[1;32mbye...33[m")"

But why not just
change all the single quotes in your Python code to double quotes,
and put the entire Python script into single quotes?

#!/bin/bash

python3 -c '
a = input("?>")
print("you typed", a)
print("33[1;32mbye...33[m")'

Similarly,

$ python3 -c "print('An odd string:', '$((6*7))')"
An odd string: 42

$ python3 -c 'print("An odd string:", "$((6*7))")'
An odd string: $((6*7))
Answered By: nadapez

I know this post is old, but I thought that I would share my code that is a working example.

#!/bin/bash
printf "This is BASHn"
printf "Please enter some text: "; read ans
export ans

cat << EOF > pyscript.py
#!/usr/bin/python3 -tt
import subprocess

print('............This is Python')
subprocess.call(["echo","............$ans"])
print('............Done with Python')

EOF

chmod 770 pyscript.py

./pyscript.py

printf "This is BASH againn"
exit 0
Answered By: jnlickey

Here’s a funnier way of doing it:

#!/bin/bash

"""" 2>/dev/null
# BASH CODE STARTS HERE

echo "Hello world from Bash!"

# BASH CODE ENDS HERE

python3 $0
exit
"""

# PYTHON CODE STARTS HERE

print("Hello world from Python!")

# PYTHON CODE ENDS HERE

Save this to a file, chmod +x it and execute it:

localhost:~# ./pysh
Hello world from Bash!
Hello world from Python!

An "explanation"

This silly script is actually a polyglot: it means something in two different programming languages (in our case, shell scripting and Python).

By making Python think the Bash section of the script is just a docstring literal, and by deviously tricking the shell into stopping execution before the "meaningless" (Python) part of the script is reached, we can have a file that works both as a Bash script and as a Python program.

(The 2>/dev/null part redirects STDERR from the """" command to the null device, thus preventing Bash from displaying an error)

If you need a more complex bash script (you need to actually do stuff in Bash after executing the Python code), you can define functions above and invoke them before the exit line. Enjoy 😛

Answered By: Manchineel
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.