Recently I decided to update and re-tag my music collection, which had suffered at the hands of the untrained and uncaring for far too long. The album art in particular, comprised of various jpg files and scattered throughout the numerous artist and album directories, was incomplete and/or inaccurate. I decided I needed a way to quickly and efficiently remove this old album art before starting the re-tagging process. Enter xargs, a handy little utility in Linux and Unix operating systems used to construct a list of arguments for an arbitrary Linux or Unix command. xargs is a good companion for commands like find, locate and grep that output long lists of files. The general syntax for the xargs command is as follows:
1 |
xargs [option...] [command [initial-arguments]] |
Let’s take the case of the my superfluous jpg files to see how xargs might be used in practice. We’ll start by opening a terminal and using the find command to locate these jpg files. This following command should find files ending with “.jpg” anywhere within my music directory, including sub-directories, and list them to the terminal:
1 |
find ~/music -name "*.jpg" |
By the way, in this particular example I’m passing along a directory to the find command that I know in advance I have the appropriate permissions to access, in this case my home directory. However, depending on what you’re searching for and where, the find command may return “Permission denied” because it (or rather you) lack sufficient permissions to access certain directories and files. In those cases you’ll need to preface the find command with su or perhaps sudo in order to avoid these errors.
Also be aware that the locate command offers similar capabilities to find, but instead of searching through the system’s directories and files, locate searches through a pre-built database of these directories and files. locate can produce significantly faster results using less computing resource compared to find, but requires the database to be updated regularly or else the results will be inaccurate and/or incomplete. Here’s an example of how to find our jpg files using the locate command:
1 2 |
sudo updatedb locate ~/music/*.jpg |
Okay, let’s combine the find command we used before with xargs to quickly remove the jpg files:
1 |
find ~/music -name "*.jpg" -print0 | xargs -0 rm |
In this example, the find command searches through my ~/music directory and pipes to xargs a list any files ending in “.jpg”. The xargs command then splits this list into sub-lists and calls the rm command once for every sub-list. The -print0 option in the find command prints the full file name on the standard output followed by a null character. This allows file names that contain newlines or other types of white space to be correctly interpreted xargs when it uses it’s corresponding -0 option. Using xargs is more efficient than this functionally equivalent version of the find command, which must call rm once for every single file it finds:
1 |
find ~/music -name "*.jpg" -exec rm '{}' \; |
Want to copy these jpg files to another directory instead removing them? The following two examples demonstrate how xargs can be used to accomplish that:
1 |
find ~/music -name "*.jpg" -print0 | xargs -0 cp -t ~/tmp |
1 |
find ~/music -name "*.jpg" -print0 | xargs -0 -I {} cp {} ~/tmp |
In the second example, the -I option tells xargs to replace the string {} with the argument list from the find command, in this case our list of jpg files. Note that not all versions of xargs support the {} syntax. No worries though, in those cases you can specify any string you’d like after -I; for example, the following variation replaces the string {} with x and will work just as well:
1 |
find ~/music -name "*.jpg" -print0 | xargs -0 -I x cp x ~/tmp |
Here’s another use for xargs – systematically setting permissions for a large number of directories or files. When assigning reasonably secure permissions directories and files it’s common to give directories a permission of 755 and files a permission of 644. Since the command we’d normally use in this situation – chmod [some permission] -R /path/to/some_directory – will assign the same permission level to the directory and the files, let’s use xargs to assign permissions selectively:
1 2 |
find ~/music -type f -print0 | xargs -0 chmod 644 find ~/music -type d -print0 | xargs -0 chmod 755 |
Using this approach, for example, we could set all the mp3 files in ~/music to read-only so that an application or script doesn’t accidentally overwrite their tag metadata:
1 |
find ~/music -name "*.mp3" -print0 | xargs -0 chmod 644 |
To verify that the permissions were set correctly let’s pass ls -l to xargs:
1 |
find ~/music -name "*.mp3" -print0 | xargs -0 ls -l |
There ya have it. A couple of examples of how to use the xargs utility, one of the most useful and the most underappreciated utilities in *nix toolbox.