Previously on Dec 12 I showed how you can execute a command on files matching a pattern with find -exec. However, it has some limitations. First it obviously only works for find. Second the exec doesn’t have a shell, meaning you can’t use it with many of the cool shell tricks you are learning about in this series of post.

The xarg command (short for “extended arguments”) doesn’t have these limitations. It works for any other command.

The basic idea is that it reads from stdin and executes another command for each item in the input.

Here is a simple example:

ls | xargs echo

It uses ls to list files in current working directory then pipe the output to xargs which will run echo for each filename. Just using xargs with echo command isn’t very interesting. So let’s look at a more useful example.

Say I want to add all images from my phone to a compressed archive file for easy backup.

find ~/Pictures -name "P_*.jpg" -type f -print0 | xargs -0 tar -cvzf images.tar.gz

I got all my images in ~/Pictures. Images taking with my phone has a filename that starts with “P_” and ends with “.jpg”. tar -cvzf add files to a compressed archive.

By default, xargs will use whitespace characters as separator between items. That would create problems if we have files with a space in the name. So the -print0 flag is used output filenames separated null character, and -0 tells xargs to separate based on null character.

Instead of archiving, we could just copy the files directly to a backup location.

find ~/Pictures -name "P_*.jpg" -type f -print0 | xargs -0 -I {} cp {} /mnt/backup/images

Where {} is used as placeholder for the filename.

There are many other ways that xargs can be used. Say we have a file “filenames.txt” with a folder structure. Could look like:

apps/frontend/
apps/backend/
libs/
scripts/

Then we can create folders matching the structure with:

cat filenames.txt | xargs mkdir -p

The xargs command is super powerful and can be used with other commands in countless ways. It allows for neat one-lines, with explicit loops.