Bash one-liners that save your afternoon: pipes, xargs and friends

Discover 10 practical Bash one‑liners using pipes, xargs and friends, with clear breakdowns and a hands‑on example you can run right now.

By Asahluma Tyika

Introduction: Why Bash One‑liners Matter

If you spend any time in a Linux terminal, you’ll quickly learn that the real magic happens when you chain tiny commands together. A single line can search, transform, and act on files without opening an editor or writing a full script.

Who is this for?

  • New developers who know the basics of ls, cat, and grep.
  • Sysadmins who want to replace repetitive loops with a single pipeline.
  • Anyone who’d rather spend an afternoon debugging a script than typing the same 20‑line routine over and over.

In this tutorial we’ll explore 10 composable one‑liners built from the classic trio pipes (|), xargs, and friends. Each command is explained step‑by‑step, so you can see exactly why it works and how to adapt it.


Part 1 – The Basics of Pipes

A pipe (|) takes the standard output of the command on its left and feeds it as standard input to the command on its right. Think of it as a conveyor belt: each tool does a small job and passes the result along.

# One‑liner What it does Breakdown
1 ls -1 *.log \| wc -l Counts how many .log files are in the current directory. ls -1 *.log lists each log file on its own line. wc -l counts those lines.
2 ps aux \| grep '[s]sh' \| awk '{print $2}' Prints the PIDs of all active SSH sessions. ps aux lists processes. grep '[s]sh' finds “ssh” without matching the grep itself. awk '{print $2}' extracts the PID column.
3 cat /var/log/syslog \| grep -i error \| tail -n 5 Shows the last 5 error messages from syslog. cat streams the log, grep -i error filters case‑insensitively, tail -n 5 keeps the final five lines.

Why use pipes?

  • No temporary files are created.
  • Each component stays tiny and testable.

Part 2 – Supercharging with xargs

xargs reads items from stdin and builds command lines. It’s perfect when a command doesn’t accept stdin but needs arguments.

# One‑liner What it does Breakdown
4 find . -name '*.tmp' -print0 \| xargs -0 rm -v Safely deletes every *.tmp file, handling spaces in names. find emits null‑terminated names (-print0). xargs -0 reads those names and runs rm -v on batches.
5 git diff --name-only \| xargs -d '\n' wc -l Shows the total line count change across all modified files. git diff --name-only lists changed files. xargs -d '\n' wc -l runs wc -l on each, then aggregates.
6 cat urls.txt \| xargs -n 1 -P 5 curl -O Downloads up to 5 URLs in parallel, one per line. xargs -n 1 passes one URL at a time. -P 5 allows 5 concurrent curl -O processes.

Tips:

  • Use -0 with find -print0 to avoid trouble with spaces, newlines, or quotes.
  • -n N controls how many arguments per invocation; -P M sets parallelism.

Part 3 – Combining find, grep, cut, sort, uniq

When you need to filter, reshape, and deduplicate data, the classic text‑processing toolbox shines.

# One‑liner What it does Breakdown
7 find /var/log -type f -mtime -2 \| xargs grep -H 'failed login' \| cut -d: -f1 \| sort \| uniq -c Counts how many recent log files contain “failed login”. find selects files modified in the last 2 days. xargs grep -H prints matching lines with filenames. cut -d: -f1 keeps just the filename. sort orders them, uniq -c counts occurrences.
8 awk -F: '{print $3}' /etc/passwd \| sort -n \| uniq -c \| sort -nr Shows how many users share each UID, highest count first. awk -F: extracts the UID field (3rd). sort -n numeric sort. uniq -c counts duplicates. Final sort -nr orders by count descending.
9 du -h . \| sort -h \| tail -n 5 Lists the five biggest items in the current directory (human‑readable). du -h . reports disk usage. sort -h understands size suffixes (K, M, G). tail -n 5 keeps the largest five.
10 git log --pretty=format:'%h %ad %s' --date=short \| grep '^a' \| nl Numbers all commits whose hash starts with “a”, showing date and subject. git log formats each commit on one line. grep '^a' keeps lines where the short hash begins with “a”. nl adds line numbers.

These one‑liners are composable: you can pipe the output of #7 into #4, for example, to delete the offending files automatically.


Hands‑On Example: Clean Up Old, Empty Log Files

Let’s put a few of the tools together into a single, safe command that:

  1. Finds .log files older than 30 days.
  2. Checks they are empty (size 0).
  3. Deletes them, printing each deletion.
#!/usr/bin/env bash
# Find empty .log files older than 30 days and delete them verbosely.

find . -type f -name '*.log' -mtime +30 -size 0 -print0 |
xargs -0 rm -v

Run it step‑by‑step

# 1. List what would be deleted (dry run)
find . -type f -name '*.log' -mtime +30 -size 0 -print0 |
xargs -0 echo "Would delete:"

# 2. Actually delete
find . -type f -name '*.log' -mtime +30 -size 0 -print0 |
xargs -0 rm -v

Explanation

  • -type f ensures we only look at regular files.
  • -mtime +30 selects files modified more than 30 days ago.
  • -size 0 restricts to empty files.
  • -print0 + xargs -0 guarantees filenames with spaces or newlines are handled correctly.
  • rm -v prints each removal, giving you immediate feedback.

You can copy the script into a file called clean_old_logs.sh, make it executable (chmod +x clean_old_logs.sh), and run it from any project directory.


Common Mistakes & How to Fix Them

Mistake Why it Happens Fix
Forgetting -print0 with find and using plain xargs. Filenames containing spaces cause xargs to split them incorrectly. Always pair find … -print0 with xargs -0.
Using grep without quoting special characters. Shell expands characters like * before grep sees them. Quote the pattern: grep '[s]sh' or grep -F "pattern" for literal matches.
Running xargs on a huge list and hitting the argument‑length limit. xargs builds command lines up to the system’s max size; exceeding it aborts. Let xargs split automatically (default) or set a smaller batch size with -n.
Assuming wc -l will give you the total count after a pipeline. wc -l counts lines per file when given arguments, not the combined total. Use wc -l without arguments at the end of the pipeline, or sum with awk '{s+=$1} END{print s}'.
Mixing sort -h with locales that treat “M” and “G” differently. Some locales sort strings alphabetically, breaking size order. Set LC_ALL=C before the pipeline: LC_ALL=C sort -h.

Try It Yourself

Exercise: Write a one‑liner that finds all Python (*.py) files in the current directory tree, counts how many times the word TODO appears in each, and prints the filenames sorted by the highest count first.

Hint: Use grep -c, sort -t: -k2 -nr, and remember to handle spaces in filenames.


What’s Next

  • Advanced xargs: Learn about -I{} placeholders for inserting arguments anywhere in the command line.
  • Process substitution (<(…)) to replace temporary files in pipelines.
  • Parallel execution with GNU parallel for massive speed‑ups.
  • Custom Bash functions that wrap these one‑liners into reusable tools.

Bookmark this page for your daily Bash toolkit!

Share: X (Twitter) Facebook LinkedIn