Submind YouTube summaries
Thumbnail for The find command: exec and xargs

The find command: exec and xargs

Watch on YouTube

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.