Why Bash One-Liners Save Your Afternoon
We have all had afternoons derailed by repetitive grunt work: cleaning up stale Git branches one by one, hunting down whatever rogue process is hogging port 3000, or digging through a 500 MB access log to find out why a server spiked at 2:00 AM.
You don’t need a full Python script or a third-party GUI tool for these tasks. The standard Unix toolkit—tools like grep, awk, sort, uniq, and xargs linked together by the pipe operator (|)—can solve them in seconds.
This guide is for developers who know basic commands like cd, ls, and mkdir, but want to link them together to solve real daily workflow problems. Here are 10 battle-tested, composable one-liners broken down in plain English.
Part 1: Finding and Inspecting Disk & Text Bottlenecks
Pipes pass the standard output (stdout) of one program directly into the standard input (stdin) of the next. Think of each command as an assembly line worker performing one specific transform.
1. Spot the Top 10 Disk Hogs in Your Current Directory
du -ah . | sort -rh | head -n 10
- What it does: Lists every file and folder in the current directory with human-readable sizes, sorts them from largest to smallest, and prints the top 10.
- Component breakdown:
| Tool | Flag | Purpose |
|---|---|---|
du |
-ah . |
Estimates file space usage for all files (-a) in human-readable units (-h) starting at . |
sort |
-rh |
Sorts lines using human-readable numeric values (-h) in reverse/descending order (-r) |
head |
-n 10 |
Cuts off the stream, outputting only the first 10 entries |
2. Extract Top 5 Most Frequent IP Addresses from an Access Log
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -n 5
- What it does: Grabs the first column of an Apache or Nginx log file (usually the client IP), groups duplicates, counts their occurrences, and ranks the most frequent visitors.
- Plain-English breakdown:
awk '{print $1}' access.logreads the file and outputs only the first whitespace-separated column.sortalphabetizes the IPs. (This step is required becauseuniqonly detects adjacent duplicate lines).uniq -ccollapses duplicates and prefixes each line with its frequency count.sort -nrsorts numerically (-n) in descending order (-r).head -n 5gives you the top 5 IPs hitting your server.
3. Tally HTTP Response Codes in Real Time
grep -oE "HTTP/[0-9.]+ [0-9]{3}" access.log | sort | uniq -c | sort -nr
- What it does: Filters out log clutter to isolate just the HTTP version and status codes (like
HTTP/1.1 200orHTTP/1.1 404), aggregating their total counts. - Key trick: The
-oflag tellsgrepto output only the matching text instead of the entire line, while-Eenables extended regular expressions.
Part 2: Taming Stubborn Processes and Ports
When local dev servers crash uncleanly, they often leave phantom processes behind. Instead of reaching for a system restart, clear them instantly.
4. Kill Whatever Process is Hogging a Specific Port
lsof -ti :3000 | xargs kill -9
- What it does: Instantly frees up port
3000by finding the Process ID (PID) listening on it and terminating it. - Component breakdown:
lsof -ti :3000:lsoflists open files and ports.-toutputs purely terse PIDs (no headers, no user info), and-i :3000limits the check to port 3000.xargs kill -9:xargstakes standard input lines and turns them into arguments for another command. Here, it transforms raw PID numbers intokill -9 <PID>.
5. Kill Multiple Runaway Scripts by Name
pgrep -f "worker.py" | xargs kill -15
- What it does: Safely sends a termination signal (
SIGTERMor-15) to all processes running a Python script namedworker.py. - Pro-tip: Start with
-15to let the program clean up database connections and temp files. Only escalate tokill -9if the process ignores the signal.
6. Show the Top 5 Memory-Consuming Processes
ps aux --sort=-%mem | awk 'NR<=6 {printf "%-8s %-6s %-6s %s\n", $1, $2, $4, $11}'
- What it does: Displays user, PID, memory percentage, and command path for the top 5 memory hogs without needing to launch heavy interactive utilities like
toporhtop. - Component breakdown:
ps aux --sort=-%mem: Gathers all system processes and sorts them descending by memory usage.awk 'NR<=6 ...': Limits output to the header plus the first 5 records (NR <= 6), printing neatly formatted columns.
Part 3: Batch Operations with xargs and find
While standard piping feeds data into a program’s standard input, many Linux utilities (like rm, mv, or git) require arguments passed to them directly. That is where xargs shines.
7. Search and Replace a String Across Project Files
grep -rl "http://localhost:8080" ./src | xargs sed -i 's|http://localhost:8080|https://api.example.com|g'
- What it does: Scans the
./srcdirectory, finds every file containing the local URL, and updates it in-place to the production URL. - Component breakdown:
grep -rl: Recursively (-r) looks through files and outputs only their file paths (-l), skipping match details.sed -i 's|old|new|g': Stream editor performing in-place (-i) global substitution. We use pipe delimiters (|) instead of slashes (/) so we don’t have to escape slashes in URLs.
8. Download Multiple Assets in Parallel
cat urls.txt | xargs -n 1 -P 4 curl -s -O
- What it does: Downloads a list of URLs saved in
urls.txt4 at a time instead of waiting for them sequentially. - Component breakdown:
| Flag | Meaning | Function |
|---|---|---|
-n 1 |
Max arguments | Passes exactly 1 URL per curl command execution |
-P 4 |
Max processes | Runs up to 4 concurrent worker processes at once |
curl -s -O |
Silent / Remote name | Downloads silently and saves the file using its remote filename |
9. Delete Merged Git Branches in One Go
git branch --merged | grep -vE "^\*|main|master|develop" | xargs -r git branch -d
- What it does: Cleans up local Git branches that have already been merged into your current branch, while protecting critical branches like
mainor active work. - Component breakdown:
git branch --merged: Lists local branches merged into the current HEAD.grep -vE "^\*|main|master|develop": Inverts matching (-v), filtering out the currently checked out branch (prefixed with*) and protected trunk branches.xargs -r: The-rflag prevents Git from running if the input is empty, avoiding error warnings when your branches are already clean.
10. Safely Purge Empty Files from a Directory Tree
find . -type f -empty -print0 | xargs -0 -r rm -v
- What it does: Recursively locates zero-byte files and safely removes them, properly handling files that contain spaces or special characters in their names.
- The magic trick:
-print0and-0ensure that filenames are separated by null bytes (\0) rather than spaces or newlines.
Hands-on Example
Let’s test these concepts in an isolated sandbox. Open your terminal, paste this block, and watch the tools work together:
# 1. Create a safe sandbox directory
mkdir -p /tmp/bash_sandbox && cd /tmp/bash_sandbox
# 2. Generate dummy access log
cat << 'EOF' > access.log
192.168.1.10 - - [10/May/2024:14:00:01] "GET /api/v1/users HTTP/1.1" 200
10.0.0.5 - - [10/May/2024:14:00:02] "POST /api/v1/auth HTTP/1.1" 401
192.168.1.10 - - [10/May/2024:14:00:03] "GET /favicon.ico HTTP/1.1" 404
172.16.0.4 - - [10/May/2024:14:00:04] "GET /api/v1/users HTTP/1.1" 200
192.168.1.10 - - [10/May/2024:14:00:05] "GET /dashboard HTTP/1.1" 200
EOF
# 3. Create dummy project files
mkdir -p src
echo "const API = 'http://localhost:8080';" > src/app.js
echo "const MOCK = 'http://localhost:8080';" > src/mock.js
touch src/empty_cache.tmp
# 4. Run our pipeline: Count requests per IP
echo "=== Requests per IP ==="
awk '{print $1}' access.log | sort | uniq -c | sort -nr
# 5. Run our search & replace pipeline
echo "=== Updating API URL ==="
grep -rl "http://localhost:8080" ./src | xargs sed -i 's|http://localhost:8080|https://api.example.com|g'
cat src/app.js
# 6. Delete empty file safely
echo "=== Removing empty files ==="
find . -type f -empty -print0 | xargs -0 -r rm -v
# 7. Clean up sandbox
cd ~ && rm -rf /tmp/bash_sandbox
Common Mistakes / Troubleshooting
- File paths with spaces breaking
xargs: By default,xargssplits on whitespace. If you have a file namedUser Report.pdf, it will try to run your command onUserandReport.pdfseparately. Fix: Always pairfind ... -print0withxargs -0. sed -icrashing on macOS: macOS uses BSDsed, which requires an empty extension string for in-place edits (sed -i '' 's/.../...'), whereas GNUsedon Linux does not accept empty quotes. Fix: If writing scripts meant to run across both platforms, use temporary files or installgnu-sedon Mac (gsed).- Accidentally running destructive commands without checking: Running
xargs rmorxargs killdirectly on untracked input can wipe files or crash servers. Fix: Pipe tocatorechofirst (e.g.,... | xargs echo rm) to preview what arguments will be executed before running the real command. - Forgetting that
uniqrequires sorted input: Runninguniq -con unsorted data only counts consecutive identical lines, returning incorrect tallies. Fix: Always placesortdirectly beforeuniq.
Try It Yourself
Navigate to any active coding repository on your machine and run a pipeline that counts lines of code across all JavaScript or Python files, sorted from smallest to largest file:
find . -name "*.js" -not -path "*/node_modules/*" | xargs wc -l | sort -n
(If you are in a Python project, swap *.js for *.py and remove the node_modules exclusion).
What’s Next
- Explore standard file descriptors: mastering
2>&1, stderr redirection, and process substitution (<()). - Write defensive Bash scripts using
set -euo pipefailso your pipelines fail cleanly when errors occur. - Look out for our upcoming post: “Mastering awk and jq for Devs Who Hate Manual Data Entry.”
Bookmark this cheat sheet so you never have to Google port-killing syntax again.