Learn by reading through in order

xargs — Build Commands from Standard Input

Lay standard input out as arguments with echo a b | xargs echo, run one word at a time with -n1, drop values into {} with -I{}, and batch-process find . -name '*.log' | xargs — with diagrams and a live terminal.

Turn Standard Input into Arguments — xargs and -n1

A pipe passes the previous command's output as the next command's standard input. But rm and echo don't read standard input — they only act on the values written as arguments. xargs is the command that takes what it receives on standard input and rearranges it into arguments for the command you write after it, so with echo a b | xargs echo, the a and b become arguments to the trailing echo.

By default, xargs passes the words it receives to a single run, batched together as much as possible. Add -n1 and it splits them up, running the command once per word.

SyntaxWhat it does
| xargsLay out the input as arguments and run the command
xargs -n1Run the command once per argument
xargs -I{}Replace {} with the input and drop it in anywhere
find ... | xargsRun a single batch of processing on what was found
| xargs echo rmPrint the command that would run, to check it first
xargs rearranges input into arguments
echo a b cstandard inputa b c| xargs echo| xargs -n1 echoecho a b cbatched, 1 runecho a / b / c1 word each, 3 runsoutputpipe it inpipe it inruns onceruns per word
echo's output is piped to xargs as standard input and rearranged into arguments. One batched run, or three runs one word at a time — that's the difference -n1 makes.
printf 'one two three\n' | xargs echo got:        # got: one two three (batched, 1 run)
printf 'one\ntwo\nthree\n' | xargs -n1 echo item:  # item: one / item: two / item: three

① Create a 3-line source file with printf 'red\ngreen\nblue\n' > colors.txt.

② Pipe the output of cat colors.txt into xargs, laying the words out as arguments to echo to print them all in one batched run.

③ Pass the same input to xargs with the option that splits it one word at a time, and confirm that echo runs three times, one line each. (When you run it correctly, an explanation will appear.)

Linux console
0 / 3 completed
Loading Linux Terminal...

The Replace String and find Integration — -I{}

xargs -I{} builds the command by dropping each line of input into the position of `{}`. Since {} can go anywhere you like, including the middle of the command, you can run a form like echo file_{}.txt — with fixed text around the value — one line at a time.

When you want to run something on the files find turns up, the find ... | xargs form is the standard. xargs lays out the paths that find prints as arguments and runs a single batch of processing over the search results. Combine it with -I{} and you can process each path found by dropping them one at a time into `{}`.

Processing what find turns up with xargs
find . -name '*.log'a.logb.log| xargs -I{} echo {}drop each lineinto {}echo a.logecho b.logprints pathspipe it inruns line 1runs line 2
The paths find prints are passed to xargs as one line = one item, and -I{} drops each into `{}` and runs them one at a time.
printf 'alpha\nbeta\n' | xargs -I{} echo 'name = {}'   # name = alpha / name = beta
mkdir -p logs                                          # create the source directory
touch logs/a.log logs/b.log                             # create 2 files
find logs -name '*.log' | xargs -I{} echo 'found {}'    # found logs/a.log / found logs/b.log

① Add the replace-string option to printf 'cat\ndog\n' | xargs and print each input dropped into the {} in pet = {}.

② Create a directory with mkdir -p data, then create two files with touch data/x.txt data/y.txt.

③ Pipe the output of find data -name '*.txt' into xargs and use the replace string to drop each path into the {} in echo 'hit {}'.

④ Also run the plain find data -name '*.txt' | xargs echo and compare it with the form where, without -I{}, the paths line up at the end.

Linux console
0 / 5 completed
Loading Linux Terminal...

Processing One at a Time — Choosing Between -n1 and -I{}

Both -n1 and -I{} run the command one item at a time, but they differ in where the value goes and how the input is split. -n1 passes words (chunks separated by spaces or newlines) one by one as trailing arguments to the command. -I{} takes lines one by one and drops them into the position where you wrote `{}`.

Use `-n1` when you just need the value at the end, and `-I{}` when you want fixed text around the value, like {}.bak.

Aspect`-n1``-I{}`
Where the value goesLines up at the end of the commandGoes where you wrote {}
Unit of splittingWords (split on spaces/newlines)Lines (one line = one item)
Best forJust passing arguments in turnBuilding a form with fixed text around the value
printf 'a\nb\n' | xargs -n1 echo prefix       # prefix a / prefix b (at the end)
printf 'a\nb\n' | xargs -I{} echo {}_done      # a_done / b_done (dropped in mid-command)

① Add the option that runs one word at a time to printf 'log1\nlog2\n' | xargs, passing them one by one as arguments to echo file.

② Pass the same input to xargs and use the replace-string option to drop them into the {} in echo {}.bak.

③ Compare how the output changes between lining up at the end and being dropped in mid-command.

Linux console
0 / 2 completed
Loading Linux Terminal...

Batch Processing in Practice — Check Before You Run

In real work, you use xargs for batch copies and batch deletes over the targets find collects. Since -I{} can drop the same value into two or more spots, it works with commands that take two arguments like cp source dest, letting you create "original name + .bak" backups all at once.

Don't run irreversible operations like rm straight away. If you run xargs echo rm before xargs rm, the command that would run is merely printed and nothing gets deleted. Check the listed targets, then drop the echo and run it for real — this check-then-run, two-step approach is the safe way to go.

Check a batch delete by printing before running
find . -name '*.tmp'a.tmpb.tmp| xargs echo rm| xargs rmrm a.tmp b.tmpjust printeddeletes bothfiles at onceprints targets① check first② once verifiednothing deletedrun for real
For irreversible operations, slip an echo in before rm to check the targets by printing them first, then run.
mkdir -p cache
touch cache/a.tmp cache/b.tmp
find cache -name '*.tmp' | xargs echo rm   # just prints rm cache/a.tmp cache/b.tmp
find cache -name '*.tmp' | xargs rm        # run for real once verified

① Create a working directory with mkdir -p work, then create two source files with touch work/note1.txt work/note2.txt.

② Pipe the output of find work -name '*.txt' into xargs and use the replace string to copy each file to "the original name with .bak appended."

③ Confirm with ls work that two .bak files have been added.

④ Pass the output of find work -name '*.bak' to xargs, slip an echo in before the delete command, and check the delete command that would run by just printing it.

⑤ If the listed targets look fine, drop the echo, delete the .bak files all at once, and confirm with ls work again that they're gone.

Linux console
0 / 6 completed
Loading Linux Terminal...
QUIZ

Knowledge Check

Answer each question one by one.

Q1Which correctly describes what xargs does?

Q2How does printf 'a\nb\nc\n' | xargs -n1 echo behave?

Q3What does {} represent in xargs -I{}?