Bash REPL vs Scripts: When to Use Each
Every DevOps engineer faces this choice: run commands interactively in the bash REPL or write a script? Both have their place, but choosing wrong wastes time.
This guide helps you decide when to use each approach. For turning REPL work into documentation, see how to save terminal commands.
The Fundamental Difference
Bash REPL: Interactive, exploratory, immediate feedback Scripts: Automated, repeatable, self-contained
# REPL: Run, see output, decide next step
$ kubectl get pods
$ kubectl logs problematic-pod
$ kubectl delete pod problematic-pod
# Script: All steps predetermined
#!/bin/bash
POD=$(kubectl get pods -o jsonpath='{...}')
kubectl logs $POD
kubectl delete pod $POD
When to Use the Bash REPL
Exploration and Discovery
You don’t know what you’ll find:
# Exploring an unfamiliar system
$ ls /etc/
$ cat /etc/nginx/nginx.conf
$ nginx -t
$ grep -r "upstream" /etc/nginx/
Each command informs the next. Scripts can’t adapt like this.
Debugging
Problems require investigation:
$ systemctl status app
$ journalctl -u app --since "10 minutes ago"
$ strace -p $(pgrep app) -f
$ lsof -p $(pgrep app)
You follow the trail wherever it leads.
One-Time Tasks
No point scripting what you’ll never repeat:
# One-time data migration
$ pg_dump old_db > backup.sql
$ createdb new_db
$ psql new_db < backup.sql
Learning and Experimentation
Test ideas interactively:
# Figuring out jq syntax
$ echo '{"a":1}' | jq '.a'
$ echo '{"a":1}' | jq '.a + 1'
$ cat data.json | jq '.items[].name'
Immediate feedback accelerates learning.
When to Write Scripts
Repeated Tasks
If you’ll do it again, script it:
#!/bin/bash
# deploy.sh - Used weekly
set -euo pipefail
echo "Pulling latest..."
git pull origin main
echo "Building..."
docker build -t app:latest .
echo "Deploying..."
kubectl apply -f k8s/
Complex Logic
Conditionals and loops need structure:
#!/bin/bash
# health-check.sh
for service in api worker scheduler; do
status=$(curl -s "http://$service/health" | jq -r '.status')
if [[ "$status" != "healthy" ]]; then
echo "ALERT: $service is $status"
notify-team "$service is unhealthy"
fi
done
Scheduled Jobs
Cron needs scripts:
# /etc/cron.daily/backup
#!/bin/bash
pg_dump production > /backup/prod-$(date +%Y%m%d).sql
find /backup -mtime +7 -delete
Shared Procedures
Team members need consistent execution:
#!/bin/bash
# onboarding.sh - Used by every new team member
create_user "$1"
add_to_groups "$1" dev docker
setup_ssh_key "$1"
clone_repos "$1"
Error Handling Required
Production automation needs safety:
#!/bin/bash
set -euo pipefail
trap 'echo "Error on line $LINENO"; cleanup' ERR
# Safe to run automatically
The Gap Between REPL and Scripts
Neither is perfect:
REPL problems:
- Commands are lost
- Context isn’t documented
- Can’t easily share
- No error handling
Script problems:
- Takes time to write
- Rigid execution flow
- Overhead for simple tasks
- Must anticipate all cases
The Middle Ground: Executable Runbooks
Runbooks bridge REPL and scripts:
# Deploy Application
## Pre-flight checks
```bash
kubectl get nodes
kubectl get pods -n production | grep -v Running
```
## Deploy
```bash
kubectl apply -f deployment.yaml
```
## Verify
```bash
kubectl rollout status deployment/app
```
## Rollback (if needed)
```bash
kubectl rollout undo deployment/app
```
Like REPL:
- Run commands step-by-step
- See output, decide next action
- Adapt to what you find
Like scripts:
- Documented and shareable
- Repeatable process
- Version controlled
Decision Framework
| Situation | Use REPL | Use Script | Use Runbook |
|---|---|---|---|
| First time doing something | ✓ | ||
| Debugging unknown issue | ✓ | ||
| Repeated automation | ✓ | ||
| Scheduled jobs | ✓ | ||
| Operational procedures | ✓ | ||
| Incident response | ✓ | ||
| Team onboarding tasks | ✓ | ||
| Complex with human decisions | ✓ |
Converting REPL to Script
When REPL exploration becomes repeated:
# REPL session that worked
$ docker build -t app .
$ docker tag app registry/app:v1.2
$ docker push registry/app:v1.2
$ kubectl set image deployment/app app=registry/app:v1.2
# Convert to script
#!/bin/bash
set -euo pipefail
VERSION=${1:?Usage: deploy.sh VERSION}
docker build -t app .
docker tag app "registry/app:$VERSION"
docker push "registry/app:$VERSION"
kubectl set image deployment/app "app=registry/app:$VERSION"
Converting Script to Runbook
When scripts need human judgment:
# Script that often needs intervention
#!/bin/bash
kubectl delete pods -l app=api
sleep 30
kubectl get pods -l app=api
# What if pods don't come back?
# API Pod Restart
## Delete current pods
```bash
kubectl delete pods -l app=api
```
## Wait for recreation
```bash
sleep 30
```
## Verify pods are running
```bash
kubectl get pods -l app=api
```
## If pods stuck in Pending
```bash
kubectl describe pods -l app=api | grep -A5 Events
```
## If resource issues, scale down other workloads
```bash
kubectl scale deployment/batch-processor --replicas=0
```
Stew: Best of Both Worlds
Stew gives you REPL-style interactivity with script-style documentation:
- Write procedures in markdown
- Run commands with a click
- See output inline
- Share with your team
- Version control everything
Your bash REPL explorations become executable team knowledge.
Join the waitlist and stop choosing between interactive and automated.