Embedding other scripting languages in Bash
Mix It Up

© Lead Image © Nebari, Fotolia.com
Solve Bash blind spots by embedding other scripting languages into your Bash scripts to get the features you need. Pete shows you solutions for floating-point math, charting, GUIs, and hardware integration.
While Bash has a huge variety of command-line tools that you can integrate into your code, sometimes you can still get stuck. Bash is extremely powerful, but, like all programming languages, it has its weakness. Some typical areas that can be challenging when using Bash include:
- Floating-point math
- Charting
- Graphical user interfaces (GUIs)
- Hardware integration
Command-line utilities can help address many of these topics, such as bc
for floating-point math or Zenity [1] for user dialogs. While these tools are extremely useful, they may not give you the functionality or customization that you need. A common approach to solving this issue is to write standalone programs in another language, like Python, and then have your Bash script call that program.
You can also solve Bash limitations by embedding code from another scripting language (e.g., Lua, NodeJS, PHP, Python, or Tcl/Tk) within your Bash script. This method offers the advantage of keeping all the code in one script. In this article, I'll look at solving the issues of floating-point math, charting, GUIs, and hardware integration by embedding other scripting languages into Bash.
How to Embed Other Languages
There are several techniques for embedding other programming languages in Bash. For very small code bits, a string of text can be piped to the other scripting language's interpreter as follows:
$ # Use Python to find Pi $ echo "import math;print(math.pi)" | python3 3.141592653589793
Here, a string of commands are piped to Python. A semicolon is used to separate each command. To return the result to Bash, a Python print
statement is used.
Some languages, such as Julia and Python, have command-line options to pass in a string of commands (see Listing 1). Command-line options offer the slight advantage of not using a pipe or an echo
statement.
Listing 1
Passing in a String of Commands
$ # Print Hello World with Julia, using -e option $ julia -e 'main(ARGS) = println("Hello World!"); @main' Hello World! $ # Print Hello World with Python, using - c option $ python3 -c 'print("Hello World")' Hello World
The disadvantage of both approaches is that writing multiple lines of code can be awkward to manage. It's especially challenging if you are using Python with indented lines.
Another approach is to use the <<
characters for the redirection of the input. A Heredoc marker is used to identify the end of the redirected input block:
$ # Use Python to show Pi $ python3 << END > # Python code here > import math > print(math.pi) > END 3.141592653589793
In this example, an END
marker was used as a terminator for the block of text that was redirected into Python.
The Bash/Python example in Listing 2 passes in a Bash variable (a
), and then the Python output is stored in a second Bash variable (ans
).
Listing 2
Passing a Bash Variable into Python
# Pass a Bash variable into Python # Get the Python output into a Bash variable a=4 ans=`python3 << END # Python code below import math b = $((a)) + math.pi print(b) END` # Back in Bash, show the answer echo "answer is: $ans"
For my last example, a Bash variable is referenced in the redirected Python block with $((my_variable))
. To get the output from a Python embedded statement into a Bash variable, you can use backtick (`) characters around the entire command string.
Passing multiple variables between Bash and another scripting language can also be done using environment variables. When I create GUI interfaces later, I'll show an example of this.
Now that you've have an understanding of how to embed other scripting languages into Bash, I will cover solutions to some common Bash issues.
Floating-Point Math
Bash works great with integer math, but floating-point math isn't directly supported. This example returns a zero instead of the correct decimal value:
$ # Bash math of 1/3 gives 0 $ echo $(( 1 / 3 )) 0
Tools such as bc
, printf
, and awk
can be used for floating-point math. These code statements use bc
to show 1/3 with two decimals:
$ # Use bc for Bash math $ echo $(bc -l <<< 'scale=2; 1/3') .33 $ # To show a leading zero $ printf '%3.2f\n' $(bc <<< 'scale=2; 1/3') 0.33
Using Bash command-line tools works, but it can often be a little confusing to read the syntax. Listing 3 shows some examples using embed NodeJS, PHP, and Python calls within a Bash shell to solve the same 1/3 question. If you're interested in doing any advanced math or statistics, embedding another language in your code could make things a little easier.
Listing 3
Embedding Calls for Floating-Point Math
# Use other programming languages # to do math in a Bash shell # # Solve 1/3 = 0.33 (2 decimals) # # NodeJS echo "Math.round(1/3*100)/100" | node -p # PHP echo '<?php print round(1/3,2);?>' | php # Python echo 'print(round(1/3,2))' | python3
Charting
Charting in Bash is usually limited to text-based graphics. There are some powerful command-line charting options such as Gnuplot [2] that can be used, but these tools may not have all the features that you need. Scripting languages like Julia, Python, and R have advanced charting options that should meet most of your application requirements.
One such charting limitation is speedometer charts. While not supported in Gnuplot, speedometer charts are available in the Python tk_tools library [3], which can be installed with
pip3 install tk_tools
To create these charts, the script gauge2.sh
(Listing 4) uses Bash to find the CPU zone 0 and 1 temperatures (lines 6 and 7). Two gauges are created with labels and ranges (lines 19-24). The Bash temperature values are passed into the gauge objects in lines 29 and 30. Figure 1 shows output from gauge2.sh
along with the Bash commands for finding the zone 0 and 1 temperatures.
Listing 4
Bash Using the Python tk_tool Library
01 # gauge2.sh - get CPU temps then create 2 gauges 02 # - use Python tk_looks library for the gauges 03 #!\bin\bash 04 05 # Get CPU temp for zone 0 and 1 (value is in milli_DegC) 06 zone0=$(cat /sys/class/thermal/thermal_zone0/temp) 07 zone1=$(cat /sys/class/thermal/thermal_zone1/temp) 08 09 #Python Code - Redirect input with "<<" until END statement 10 python3 << END 11 # Python Two Gauge Example 12 import tkinter as tk 13 import tk_tools 14 15 root = tk.Tk() 16 root.title('CPU Temperature Zones 0 and Zone 1') 17 18 # Create 2 gauges 19 gauge0 = tk_tools.Gauge(root, max_value=70.0,\ 20 label='Zone 0 Temp', unit='Deg C',\ 21 width=600, height=300) 22 gauge1 = tk_tools.Gauge(root, max_value=70.0,\ 23 label='Zone 1 Temp', unit='Deg C',\ 24 width=600, height=300) 25 gauge0.grid() 26 gauge1.grid() 27 28 # Update the zone temps, divide by 1000 for DegC 29 gauge0.set_value($((zone0)) / 1000) 30 gauge1.set_value($((zone1)) / 1000) 31 32 root.mainloop() 33 34 END
The popular, well-documented Python Matplotlib library [4] is another excellent option for building different chart types. In Listing 5, the Bash script bars3.sh
is used to gather memory usage data from vmstat
, the virtual memory stats tool (lines 7-9). Embedded Python code is used to create a Matplotlib bar chart (lines 24-35). The chart data is configured with Bash variables (line 20) using the syntax of $((bash_variable))
within the redirected Python code block. Figure 2 shows vmstat
's results along with the bars3.sh
script output using a Matplotlib bar chart.
Listing 5
Bash Using a Python Matplotlib Chart
01 # bars3.sh - pass Bash data to an embedded Python call 02 # - get vmstat data into Bash variables 03 # - use matplotlib bar chart to show Bash data 04 #!\bin\bash 05 06 # Get vmstat data in kbytes 07 vmfree=$(vmstat | awk 'NR == 3 {print int($4/1000)}') 08 vmbuff=$(vmstat | awk 'NR == 3 {print int($5/1000)}') 09 vmcache=$(vmstat | awk 'NR == 3 {print int($6/1000)}') 10 11 12 # Python Code to create 3 vertical bars 13 # Bash variables are passed as data values 14 # Redirect input with "<<" until END statement 15 python3 << END 16 import numpy as np 17 import matplotlib.pyplot as plt 18 19 # creating the dataset using Bash variables 20 data = {'Free':$((vmfree)), 'Buffer':$((vmbuff)), 'Cache':$((vmcache))} 21 features = list(data.keys()) 22 values = list(data.values()) 23 24 fig = plt.figure(figsize = (10, 5)) 25 26 # creating the bar plot and add values on the bars 27 plt.bar(features, values, width = 0.4) 28 for i in range(len(features)): 29 plt.text(i,values[i],values[i]) 30 31 plt.xlabel("Memory Value") 32 plt.ylabel("kbytes") 33 plt.title("Show Bash VMSTAT Data in Matplotlib") 34 35 plt.show() 36 END
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

News
-
System76 Releases COSMIC Alpha 7
With scores of bug fixes and a really cool workspaces feature, COSMIC is looking to soon migrate from alpha to beta.
-
OpenMandriva Lx 6.0 Available for Installation
The latest release of OpenMandriva has arrived with a new kernel, an updated Plasma desktop, and a server edition.
-
TrueNAS 25.04 Arrives with Thousands of Changes
One of the most popular Linux-based NAS solutions has rolled out the latest edition, based on Ubuntu 25.04.
-
Fedora 42 Available with Two New Spins
The latest release from the Fedora Project includes the usual updates, a new kernel, an official KDE Plasma spin, and a new System76 spin.
-
So Long, ArcoLinux
The ArcoLinux distribution is the latest Linux distribution to shut down.
-
What Open Source Pros Look for in a Job Role
Learn what professionals in technical and non-technical roles say is most important when seeking a new position.
-
Asahi Linux Runs into Issues with M4 Support
Due to Apple Silicon changes, the Asahi Linux project is at odds with adding support for the M4 chips.
-
Plasma 6.3.4 Now Available
Although not a major release, Plasma 6.3.4 does fix some bugs and offer a subtle change for the Plasma sidebar.
-
Linux Kernel 6.15 First Release Candidate Now Available
Linux Torvalds has announced that the release candidate for the final release of the Linux 6.15 series is now available.
-
Akamai Will Host kernel.org
The organization dedicated to cloud-based solutions has agreed to host kernel.org to deliver long-term stability for the development team.