# When to Reach for Another Language

Bash is at its best gluing programs, files and folders together on any Linux server or Mac; when a script needs real data handling, grows into many files of logic or has to run for Windows users, Python, JavaScript or C# fits better, and a bash script can hand the hard part to a program in one of them.

Journeyman · Unix · Linux · Updated November 10, 2026

## After this lesson you can

- Name the jobs bash is best at, and the signs that a script should become a program in Python, JavaScript or C#
- Have a bash script hand one job to a program in another language, such as a Python script that does the math

## Key takeaways

- Bash is best at gluing programs together, handling files and folders, starting things, and short jobs on any Linux server or Mac.
- Signs a script wants another language: decimals, dates and nested data; hundreds of lines of logic; users on Windows without WSL; a window or a web page.
- Python suits data and reports, JavaScript suits a project that's already a website, and C# suits larger apps and Windows.
- Both can work together: bash runs the steps and calls a Python, JavaScript or C# program for the part bash is bad at.
- #!/bin/sh is the smaller shell found everywhere. Write for it only when bash isn't there, because [[ ]] and arrays aren't.

The bakery's sales script started as twenty lines: read the day's sales, add them up, save a report. A year later it's four hundred. Prices have cents, so it multiplies by 100 before every sum, because `$(( ))` counts only whole numbers (*Values from Commands: $( ) and $(( ))*). A cake called *cake, birthday* broke the CSV reading (*CSV Files in Bash, and Their Limits*). Every new feature breaks an old one. Nothing is wrong with you or with bash: the script has outgrown the job bash is built for. Knowing when that happens is part of being good at bash, and a developer who can say "this part should be Python" saves a team weeks.

## What bash is best at

Bash is a **scripting language**: a language for directing other programs. That's its strength, and the course has used it all along:

- **Gluing programs together:** run this, then that, only if it worked, with the output of one fed to the next.
- **Files and folders:** copying, moving, renaming, backing up, cleaning up.
- **Starting things:** a dev server, a deploy, a scheduled job, a project's scripts.
- **Being there already:** every Linux server and every Mac has a shell, with nothing to install.

A deploy script, a backup, a `setup.sh`: short jobs made of commands. Writing them in another language usually means more lines, and calling the same commands anyway.

## Signs a script wants to be a program

None of these is a hard rule. Each one is a reason to stop and ask:

- **Real data:** decimals, dates and time zones, CSV files with quoted commas, data inside data (an order that holds a list of cakes, each with its own price). Bash's arrays are one level deep, and its math is whole numbers only.
- **Lots of logic:** hundreds of lines, many functions passing values around, and tests that are hard to write.
- **Windows users:** a bash script needs bash. A coworker on Windows without WSL can't run it.
- **A window or a web page:** bash talks in text, in a terminal.
- **Speed over many items:** a loop that starts a program for each of 100,000 lines takes minutes where a single program takes a second.

## Python, JavaScript or C#

These are **general-purpose languages**, built for programs of any size. Three common choices, each with its strengths:

- **Python** reads well and has CSV, JSON and date tools built in, so it's a common next step for data and reports. Ubuntu has it already, and on a Mac, `brew install python` installs it.
- **JavaScript**, run with **Node.js**, fits a project that's already a website, so the team writes one language everywhere.
- **C#**, run with .NET, suits larger apps and Windows desktops, and its types catch many mistakes before the program runs. Since .NET 10, `dotnet run app.cs` runs a single file, much like a script.

There's no wrong answer among them: pick the one your team or your class already uses.

One step in the other direction: `#!/bin/sh` runs a script in the smallest standard shell, written to the **POSIX** rules that every Unix-like system follows. On Ubuntu it's a smaller shell called dash:

```bash
ls -l /bin/sh
```

```text
lrwxrwxrwx 1 root root 4 Feb  2  2026 /bin/sh -> dash
```

`[[ ]]` and arrays aren't part of it. Write for `sh` only when bash isn't installed, as in some very small containers.

## Both together

It's never bash *or* Python: options, not sides. Keep bash for the steps, and hand the hard part to a program that's good at it. Make the bakery's sales in a practice folder:

```bash
mkdir -p ~/terminal-practice/bakery-sales && cd ~/terminal-practice/bakery-sales
printf 'item,price\nsourdough loaf,6.00\nblueberry muffin,3.25\ncinnamon roll,4.50\nbirthday cake,32.00\n' > sales.csv
```

The math goes to Python. A here document (*Options and Flags: getopts and --help*) writes `total.py` without leaving the terminal:

```bash
cat > total.py <<'EOF'
import csv

with open("sales.csv") as f:
    prices = [float(row["price"]) for row in csv.DictReader(f)]

print(f"{len(prices)} sales, total ${sum(prices):.2f}, average ${sum(prices) / len(prices):.2f}")
EOF
python3 total.py
```

```text
4 sales, total $45.75, average $11.44
```

And bash does what it's good at: the folder, the file name with today's date, and running the steps in order. Save this as `report.sh` and make it runnable:

```bash
#!/usr/bin/env bash
# report.sh: saves today's sales report in the reports folder.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"

mkdir -p reports
python3 total.py > "reports/sales-$(date +%F).txt"
echo "Saved reports/sales-$(date +%F).txt"
```

```bash
./report.sh
cat reports/*.txt
```

```text
Saved reports/sales-2026-11-09.txt
4 sales, total $45.75, average $11.44
```

Your date will differ. When the report needs more, only `total.py` grows; `report.sh` stays the same few lines.

## Check yourself

2 questions to try on the lesson page.

## So what

Bash is the glue, not the whole machine: let it run the steps, and when a part needs real data handling or real size, give that part to the language built for it.

## Key terms

- [Bash](https://www.ask-codey.com/glossary/bash)
- [Scripting Language](https://www.ask-codey.com/glossary/scripting-language)
- Python
- [Node.js](https://www.ask-codey.com/glossary/node-js)
- [POSIX](https://www.ask-codey.com/glossary/posix)

## Cheat sheets

- [When to Reach for Another Language](https://www.ask-codey.com/cheat-sheets/bash-when-to-use-another-language-cheat-sheet)

## Related

- [A Script Is an Application](https://www.ask-codey.com/lessons/bash-scripts-are-applications)
- [CSV Files in Bash, and Their Limits](https://www.ask-codey.com/lessons/bash-csv-files)
- [Values from Commands: $( ) and $(( ))](https://www.ask-codey.com/lessons/bash-command-substitution)
- [Sharing Your Tool](https://www.ask-codey.com/lessons/bash-sharing-your-tool)

Source: https://www.ask-codey.com/lessons/bash-when-to-use-another-language
