Video summary
The video explores advanced techniques for processing files found by the `find` command, specifically focusing on how to execute additional commands like `ls -l` to display detailed file information rather than just listing names. The presenter introduces two primary methods for achieving this: using the built-in `-exec` action within `find` or piping the output to the external `xargs` command. When utilizing `-exec`, users can specify a command with a placeholder pair of braces `{}` to represent each found file, ensuring the shell does not expand the name prematurely by enclosing it in single quotes. The video demonstrates that using a semicolon after the command executes the action individually for every file discovered, which results in separate process calls and misaligned output columns because `ls` is run independently for each item.
To improve efficiency and formatting, the tutorial explains how to replace the semicolon with a plus sign (`+`) in the `-exec` syntax. This modification instructs `find` to accumulate all file names into a single list before passing them to the command once it has finished searching, thereby reducing system overhead and ensuring that the output columns align correctly. Alternatively, the video introduces the `xargs` method, where the output of `find` is piped directly into `xargs`, which then invokes the desired command with all file names as arguments. This approach avoids the need for semicolons or plus signs within the `find` statement itself and produces a similar result to the optimized `-exec` method, provided that file names do not contain spaces.
A critical issue addressed is the handling of file names containing spaces, which can cause significant problems when using `xargs`. Since standard output separates file names by newlines or spaces, a filename with an embedded space might be misinterpreted as multiple separate files by `xargs`, leading to errors in commands like `ls -l`. To resolve this, the presenter recommends using the `-print0` option with `find` to output file names separated by null characters instead of spaces or newlines. Consequently, when piping this output to `xargs`, one must also use the `-0` flag to tell `xargs` to expect null-separated input, ensuring that filenames with spaces are processed correctly as single entities.
In conclusion, the video summarizes that while both `-exec` and `xargs` offer valid ways to process found files, users must be mindful of file naming conventions when choosing between them. If there is a possibility of spaces in file names, the safest approach is to combine `find -print0` with `xargs -0` to guarantee accurate handling of all filenames. This combination prevents parsing errors and ensures that commands receive the complete list of files as intended, maintaining both the integrity of the data and the efficiency of the execution process.
Read the full video transcript
In a previous video, we learned how to
do file tests for the file name, file
type, file size, and modification time.
But all we are seeing from find is the
file names.
In these two examples, we'd like to see
how much larger than 100 K bytes these
files are.
Or how much after May 1st, 2025 they
are.
What we need is some way to take the
list of files and send it to a command
like ls -l to see the file information.
One of these ways is built into the find
command.
And the other is a separate command.
Let's investigate the built-in method
first.
I'm going to change to my downloads
directory.
And I'm going to find all the files that
have a size that is greater than 100 K
bytes.
And for each file, instead of printing
the name, I'm going to take a different
action.
I'm going to execute
an ls -l command
on the file that was found.
To specify the file that was found,
I put
a pair of empty braces.
They're a placeholder that means put the
file name here.
We have to put these braces in single
quotes to prevent shell expansion.
Finally, we have to tell exec that the
command is ended, and we do that with a
semicolon.
And that also has to be quoted.
Now, instead of just getting the file
names,
we'll get all the information about the
files.
Did you notice that the output columns
aren't quite lined up?
That's because find is executing the ls
command separately for each file it
finds.
That also means the computer is working
harder than it really has to.
What we'd like to do is tell find to
accumulate all the file names and put
them all into the placeholder and then
call ls -l when it's finished.
Here's how we do it. Let's bring back
the command and instead of a semicolon
to say this command is done,
we're going to use a plus sign,
which tells find that the command is
done and also to accumulate everything
instead of doing ls -l for every single
file.
And now everything lines up properly
because all of these files are having
the ls -l done at once.
The other way we can get a long list of
the files we found is to pipe the output
of find
to the xargs command.
The xargs command is followed by the
command that we want done, in this case
ls -l.
The output from find is appended after
the command. We don't need a semicolon
or a plus sign.
And we see the same result.
When you're using find, you have to
watch out for spaces in file names.
Let me clear and go back to my home
directory.
And after finishing the previous video,
I downloaded a file named
codingworkshop.pdf.
And you'll notice it has a blank in its
name.
A normal find to find all PDF files,
find. -name
star.pdf
works great.
I get the file names just as expected,
and there's coding workshop.pdf with a
space in it. No problem.
If I use exec
to get a long listing of the files,
let's do ls -l
put in my placeholder
and say that I want to accumulate the
results,
it works great and there's my file with
a space in its name.
But when I do the find
and pipe the result to xargs ls -l, now
I'm going to have a problem.
Because the output from find
is a list of file names separated by
spaces.
And because the file name contained a
space,
ls -l thinks we have two separate files
instead of one.
To fix this problem, I have to tell find
to print its results separated by a null
character.
That's a special character which is a
byte containing a zero
rather than a space or new line.
I do that by putting the action of
print0.
In fact, if I do this without doing the
pipe to xargs, you will see that
everything comes out as one gigantic
long line because the null character
that separates all the file names
doesn't display in the console.
Because the file names are now separated
by nulls,
when I pipe this to xargs,
I have to tell xargs that its input is
going to be separated by null characters
instead of spaces.
And then I can do the ls -l.
And now spaces in file names will no
longer be treated as separators,
and the file name will be handled
properly.
In summary, there are two ways to
execute a command to process the names
of the files that were found.
The exec action in the find command,
or a pipe to the xargs command.
When using xargs, if you know that there
are spaces in file names, or you think
there might be,
you need to tell find to print the file
names with a null character to separate
them, instead of a space or a new line.
And you have to tell xargs to use the
null character as its separator.