Basics

What is xargs — and why rm can't hear your pipe

Illustration: a conveyor belt carries loose paper slips, a machine ties them into bundles and feeds them to a press

Try this in a terminal:

echo old.log | rm

Looks like it should delete old.log. Instead you get:

rm: missing operand

rm didn't hear a word. The file name went into the pipe — and hit a wall. Here's the tricky part: every command has two ears, and rm only listens with one. The bridge between them is called xargs.

What xargs is

xargs is a command that takes text from its input and turns it into arguments for another command.

Before: a stream of lines a.txt b.txt c.txt. After: a call rm a.txt b.txt c.txt.

That's it. The name reads exactly like that: "x args", build the arguments.

Every command has two ears

Any terminal command can get data in two ways.

  • Standard input — a stream of text flowing through a pipe |. grep, sort, wc listen to it.
  • Arguments — the words after the command name: rm a.txt. rm, mkdir, cp, touch listen to those.

A pipe only plugs into the first ear. That's why echo old.log | rm stays silent: rm doesn't read the stream at all. It needs the name on the command line.

xargs pours one ear into the other:

echo old.log | xargs rm

Now the file is gone. xargs read old.log from the pipe and ran rm old.log itself.

The most common real example — delete everything find found:

find . -name "*.tmp" | xargs rm

Three traps everyone trips on

Spaces in names

xargs splits input on spaces, not on lines. To it, my file.txt is two files: my and file.txt. This mess is covered in detail in the article on scripts that break on spaces.

An apostrophe stops everything

We tested on a folder with three files: a.txt, it's.txt and my file.txt.

ls | xargs echo

Output:

xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
a.txt

xargs treats quotes as special. The apostrophe in it's looks to it like an opening quote with no partner. It handled the first file and silently dropped the rest. Had that been rm, a third of the files would be gone.

Empty input still runs the command

This one is the most surprising. If nothing arrives on input, GNU xargs (Linux) still runs the command — once, with no arguments:

find . -name "*.nope" | xargs ls -l

No files — yet ls -l lists the current folder. With rm you're lucky: it just says missing operand. With another command you might not be. The -r flag (--no-run-if-empty) turns this off. On macOS, xargs already skips the command on empty input.

How to use it safely

One rule fixes spaces and quotes at once: separate names with a null byte.

find . -name "*.tmp" -print0 | xargs -0 rm

-print0 makes find put a \0 between names. -0 makes xargs split only on it. A null byte can't appear in a file name. So neither a space nor an apostrophe can break anything anymore.

Four more flags worth knowing:

  • -r — don't run the command if input is empty (GNU).
  • -n 1 — one argument per run: echo "1 2 3 4" | xargs -n 2 echo prints two lines.
  • -I {} — put the value anywhere: xargs -I {} cp {} backup/.
  • -P 4 — run up to four processes in parallel. Handy when you need to compress a hundred images.

Where you'll run into it

  • In commands from other people's answers and from your AI assistant. grep -rl old | xargs sed -i ... is the classic way to replace text across many files. Now you know where the mine is: names with spaces.
  • Together with find. When to search with find and when with grep is in find vs grep.
  • When there are too many files. rm *.jpg on two hundred thousand files fails with Argument list too long: the system caps how long a command line can be. xargs splits the list into batches and calls rm several times.

When you see | xargs in an AI answer, check one thing: is there a -0? If you didn't choose the file names yourself, ask it to rewrite with -print0.

How is xargs different from a pipe?

A pipe passes text to standard input. xargs reads that text and turns it into arguments for the next command. They work together: find | xargs rm.

Can I do without xargs?

Often, yes. find has -exec rm {} + and -delete, which don't get confused by spaces. But xargs is more universal: it works with the output of any command, not just find.

Is there xargs on Windows?

Not in PowerShell. It's there in Git Bash and WSL. In PowerShell itself you do the same with ForEach-Object.

Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app
KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →