Learn › Linux Foundations › Arguments
xargs - a hands-on Linux lab on a real virtual machine.
xargs splits its input on whitespace, so a filename with a space in it tears into two arguments. Watch five files become seven tokens, prove the damage with wc -l, and learn to spot the bug on sight, all in the practice terminal.
The fixture folder ~/args-base has a files directory holding exactly five files. In a few minutes you will feed that list of five files to xargs, and xargs will hand you seven arguments back. Two extra items will appear out of nowhere, and both of them will be broken pieces of real filenames.
Where do the two ghosts come from? That is the whole lesson. By the end you will be able to spot this bug on sight, because it bites almost everyone who pipes find into xargs for the first time.
First, move into the fixture folder so every path below stays short. Remember, cd prints nothing when it works:
cd ~/args-base
prompt: student@linuxcamp:~$ answer: cd ~/args-base output: hint: Type cd, a space, then the path: cd ~/args-base
The black boxes here are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. On the real machine at the end of the module, the capstone mission rebuilds this same args-base folder, and you run these drills for real.
Remember from the xargs lesson: xargs reads text from its input and turns it into arguments for a command, and -n1 caps it at one argument per run, so the command fires once per token. The fixture file words.txt holds four words, one per line: alpha, bravo, charlie, delta.
Before you run this, decide: how many lines will come out? Four words in, -n1 on, so it should be one run of echo per word:
cat words.txt | xargs -n1 echo
prompt: student@linuxcamp:~/args-base$ answer: cat words.txt | xargs -n1 echo output: alpha bravo charlie delta hint: cat the file, pipe into xargs -n1 echo: cat words.txt | xargs -n1 echo
Four lines, exactly as you predicted. Four tokens in, four echo runs out. xargs behaved. Keep this picture in mind, because the next few screens show the exact same command shape producing the WRONG count, and the difference is a single space character.
Here is the one rule this whole lesson hangs on: xargs splits its input on whitespace. A space is a gap between tokens. A newline is a gap between tokens. To xargs, they are the same thing: token, gap, token, gap.
That is why the four words came out as four tokens even though they sat on four separate lines. Newlines were gaps. But it also means a space sitting inside a filename looks like a gap too. xargs has no way to tell "gap between two names" apart from "space inside one name".
This default is a fossil. xargs dates back to 1970s Unix, when nobody put spaces in filenames, so splitting on any whitespace was a perfectly safe choice that simply never changed.
Watch the rule work on a plain string first. One quoted argument, three words inside it. Decide before you run: will xargs -n1 treat this as one token or three?
echo "one two three" | xargs -n1 echo
prompt: student@linuxcamp:~/args-base$ answer: echo "one two three" | xargs -n1 echo output: one two three hint: Pipe the quoted words into xargs -n1 echo: echo "one two three" | xargs -n1 echo
Three lines. Your quotes made one two three a single argument to the FIRST echo, but the pipe carries only raw text. The quotes never reach xargs. It saw two spaces and split the text into three tokens. Quoting protects an argument from your shell, not from xargs downstream. Now imagine those were not words but a filename: final draft.txt.
Time to set the trap. The files folder holds five files, and two of them have a space in the middle of the name: final draft.txt and q1 report.txt. Spaces in filenames are completely legal on Linux, and out in the real world they are everywhere.
Look at the honest list first. find files -type f walks the folder and prints each file's path, one per line. Pipe it through sort so the order is stable and readable:
find files -type f | sort
prompt: student@linuxcamp:~/args-base$ answer: find files -type f | sort output: files/data.csv files/final draft.txt files/notes.txt files/q1 report.txt files/report.txt hint: find the files, then pipe through sort: find files -type f | sort
Why | sort? On its own, find prints matches in filesystem order, which is not alphabetical and can differ from one machine to the next. Piping through sort gives a stable, predictable list every time. Every find drill in this lesson ends in sort for exactly that reason.
Five files, clearly listed, two of them carrying a space in the middle of the name. Count them yourself: five lines, five names. That is the truth on disk. Now feed this exact list to xargs and watch the truth change.
Take that same sorted list and feed it to xargs -n1 echo, the shape you warmed up with. Each ARGUMENT xargs builds comes out on its own line. Commit to a prediction before you run it: five files went in, so how many lines come out? If your answer is five, the whitespace rule from two steps ago has a surprise for you:
find files -type f | sort | xargs -n1 echo
prompt: student@linuxcamp:~/args-base$ answer: find files -type f | sort | xargs -n1 echo output: files/data.csv files/final draft.txt files/notes.txt files/q1 report.txt files/report.txt hint: Take the sorted list and pipe it into xargs -n1 echo: find files -type f | sort | xargs -n1 echo
Seven lines, not five. There are your ghosts. Look at lines two and three: files/final and draft.txt. That is ONE file, files/final draft.txt, torn in half at the space. Same story with files/q1 and report.txt. xargs hit the space inside each name and, obeying its whitespace rule, called it a gap between two tokens. Note what sort did and did not do: it fixed the ORDER, but it cannot fix the SPLITTING. The split is the bug.
Seeing it is one thing; measuring it makes it undeniable. wc -l counts lines. Pipe the arguments xargs produced into wc -l and you count exactly how many tokens xargs actually saw. Decide on your number first. Five real files, two of them split in two:
find files -type f | xargs -n1 | wc -l
prompt: student@linuxcamp:~/args-base$ answer: find files -type f | xargs -n1 | wc -l output: 7 hint: Count lines at the end with wc -l: find files -type f | xargs -n1 | wc -l
This drill has no sort and still gives a stable answer. That is on purpose: wc -l just counts lines, and the count does not depend on what order find printed them in. Seven is seven no matter the order. We only need sort when the ORDER on screen has to be predictable.
7, hard proof. Five files entered, seven tokens came out, because the two space-names each became two. You have now done the full diagnosis: you predicted the failure from the whitespace rule, watched it happen, and measured it. That is exactly how you catch this bug in the wild: when the token count does not match the file count, something split.
This lesson used echo, so the damage was harmless. In real work the command after xargs is often rm, mv, or chmod. Fed a split list, it would act on files/final and draft.txt as two separate files: the job fails, or far worse, it touches the wrong thing. Never pipe raw find output into xargs when filenames might contain spaces.
So what is the fix? find and xargs share a pact: find -print0 ends each path with a NUL byte, a character that can never appear inside a filename, and xargs -0 splits only on NUL. Names stay whole. That pair is the very next lesson, so for now it is enough to recognize the bug when you see it.
You have every command you need. These three challenges show you only the goal. Recall the command shape yourself; that recall is what makes it stick.
Challenge 1. Print the honest, sorted list of every file in the files folder, one path per line, in stable alphabetical order.
prompt: student@linuxcamp:~/args-base$ answer: find files -type f | sort output: files/data.csv files/final draft.txt files/notes.txt files/q1 report.txt files/report.txt hint: You used find with a type filter, then made the order stable with a second command after the pipe.
Challenge 2. Prove the whitespace bug with a single number: count how many tokens xargs sees when it is fed the raw find list of those files.
prompt: student@linuxcamp:~/args-base$ answer: find files -type f | xargs -n1 | wc -l output: 7 hint: Three stages: find the files, let xargs emit one token per line, then count the lines. No sort needed for a count.
Challenge 3. Back to the safe word list. Print the four words of words.txt one per line, using xargs to run echo once per word.
prompt: student@linuxcamp:~/args-base$ answer: cat words.txt | xargs -n1 echo output: alpha bravo charlie delta hint: Read the file out with cat, then cap xargs at one argument per echo run.
You earned this table. Every row is something you just ran on args-base:
The one rule that ties it together: xargs splits its input on whitespace by default, and filenames are allowed to contain whitespace. When the token count disagrees with the file count, a name has been torn apart. The find -print0 plus xargs -0 fix is next.
The practice terminal has walked you through the whole pitfall. You know the rule (whitespace is always a gap to xargs), you have seen the symptom (5 files become 7 tokens), and you can prove it with a count.
The Arguments module ends with one real Linux machine: the arguments capstone mission. There a VM boots just for you and rebuilds this same args-base folder, words.txt and the five files, spaces and all. The mission hands you objectives that use exactly what you just practiced, and it shows no commands. You read the objective, recall the shape, and type it.
Next up: the fix. find -print0 and xargs -0 keep space-names whole, and that lesson is waiting for you.
Practice xargs quoting: the space-in-a-name trap in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.