Bash
The shell that automates everything.
Bash is the command shell on most Linux servers and the default scripting language for automation. Every AI engineer uses it to set up GPU machines, run training jobs, manage models and glue tools together.
Why learn Bash?
You cannot avoid the terminal in AI and cloud work. Bash lets you automate repetitive tasks, control remote GPU servers and chain powerful tools together.
- Everywhere: every Linux server, Docker container and Mac terminal has a shell.
- Automation: turn any sequence of commands into a reusable script.
- AI workflows: launch training, download models, check GPUs with nvidia-smi.
Set up and run your first program
Bash is preinstalled on Linux. macOS uses zsh by default but includes bash; on Windows use WSL.
bash --version
chmod +x hello.sh
./hello.sh#!/usr/bin/env bash
name="Ada"
echo "Hello, AI! Welcome to Bash, $name."Variables and quoting
Assign with no spaces around =. Read a variable with $name. Always wrap variables in double quotes to keep spaces intact. $(command) captures a command's output.
#!/usr/bin/env bash
model="llama3.1"
layers=32
today=$(date +%F)
echo "Model: $model, layers: $layers, date: $today"
gb=$(( 8 * 2 )) # integer arithmetic
echo "FP16 size of 8B model: $gb GB"Conditions and loops
if uses [[ ... ]] tests. for loops over lists or files; while loops until a condition fails.
#!/usr/bin/env bash
for gpu in H100 H200 B200; do
echo "Benchmarking $gpu"
done
vram=24
if [[ $vram -ge 80 ]]; then
echo "data center GPU"
elif [[ $vram -ge 24 ]]; then
echo "can run a 30B model at 4-bit"
else
echo "small models only"
fi
for f in *.txt; do [[ -e "$f" ]] && wc -l "$f"; doneFunctions and arguments
Scripts receive arguments as $1, $2 and so on; $# is the count and $@ is all of them. Functions work the same way.
#!/usr/bin/env bash
set -euo pipefail # stop on errors and unset variables
params() {
local layers=$1 width=$2
echo $(( 12 * layers * width * width ))
}
echo "Args: $# ($*)"
echo "Params: $(params 32 4096)"Pipes and text processing
The pipe | sends one command's output into another. Combined with grep, sort, awk and jq, you can process logs and JSON quickly.
#!/usr/bin/env bash
# Top 5 most common words in a file
tr -cs '[:alpha:]' '\n' < notes.txt | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn | head -5
# GPU memory use as CSV
nvidia-smi --query-gpu=name,memory.used,memory.total --format=csv
# List local Ollama models with jq
curl -s http://localhost:11434/api/tags | jq -r '.models[].name'Files, exit codes and background jobs
Every command returns an exit code (0 means success). Redirect output with > and 2>, and run long jobs in the background with & or nohup.
#!/usr/bin/env bash
mkdir -p logs
if python train.py > logs/train.log 2>&1; then
echo "training finished"
else
echo "training failed with code $?" >&2
fi
nohup python serve.py > logs/serve.log 2>&1 &
echo "server started with PID $!"AI with Bash
Bash does not train models, but it runs almost every AI workflow: setting up environments, downloading weights, launching distributed training with torchrun, scheduling jobs on clusters with Slurm and calling model APIs with curl.
The essential libraries
A training job script
A typical script that checks the GPU, logs everything and launches multi-GPU training with PyTorch's torchrun.
#!/usr/bin/env bash
set -euo pipefail
NGPU=$(nvidia-smi -L | wc -l)
RUN="run-$(date +%Y%m%d-%H%M)"
mkdir -p "runs/$RUN"
echo "Found $NGPU GPU(s); logging to runs/$RUN"
nvidia-smi --query-gpu=name,memory.total --format=csv | tee "runs/$RUN/gpus.csv"
torchrun --nproc_per_node="$NGPU" train.py --epochs 3 --out "runs/$RUN" 2>&1 | tee "runs/$RUN/train.log"Build a simple AI agent in Bash
With curl and jq you can build a small tool-calling agent. It is a great way to see exactly what goes over the wire between your code and the model.
#!/usr/bin/env bash
set -euo pipefail
URL=http://localhost:11434/v1/chat/completions
TOOLS='[{"type":"function","function":{"name":"get_weather","description":"Weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]'
MSGS='[{"role":"user","content":"Should I take an umbrella in Lahore today?"}]'
for round in 1 2 3 4 5; do
BODY=$(jq -n --argjson m "$MSGS" --argjson t "$TOOLS" '{model:"llama3.1",messages:$m,tools:$t}')
MSG=$(curl -s "$URL" -H 'Content-Type: application/json' -d "$BODY" | jq '.choices[0].message')
MSGS=$(jq --argjson x "$MSG" '. + [$x]' <<< "$MSGS")
if [[ $(jq '.tool_calls | length // 0' <<< "$MSG") -eq 0 ]]; then
jq -r '.content' <<< "$MSG"; break
fi
while read -r CALL; do
ID=$(jq -r '.id' <<< "$CALL")
CITY=$(jq -r '.function.arguments | fromjson | .city' <<< "$CALL")
RESULT="It is 24°C and sunny in $CITY."
MSGS=$(jq --arg id "$ID" --arg r "$RESULT" '. + [{role:"tool",tool_call_id:$id,content:$r}]' <<< "$MSGS")
done < <(jq -c '.tool_calls[]' <<< "$MSG")
doneFor anything bigger, move to Python or TypeScript, but keep Bash for the glue around it.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Bash learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Bash cheat sheet
| Task | Syntax |
|---|---|
| Variable | name="x"; echo "$name" |
| Command output | now=$(date) |
| If | if [[ -f file ]]; then ... fi |
| Loop | for f in *.log; do ...; done |
| Pipe | cmd1 | cmd2 |
| Redirect | cmd > out.log 2>&1 |
Common mistakes
- Spaces around
=break assignments: writex=1, notx = 1. - Unquoted variables split on spaces; quote them:
"$file". - Scripts keep running after errors unless you use
set -e.
Where to go next
- Bash Guide — trusted guide
- ShellCheck — find bugs in scripts
- The Linux Command Line — free book
On TensorCore.si: Python volume, What is a GPU cluster?.
Keyboard: [ previous language · ] next language · / search the library