April 14, 2004

SysAdmin to SysAdmin: bring out your inner xargs

Author: Brian Jones

xargs is your friend. Using xargs, you can pull off feats of greatness and not have to write a script to do it. xargs can take care of things right on the command line. Though I focus mainly on files in this article (it's what I use it for almost exclusively), it's important to remember that xargs acts on standard input, which could mean lines redirected from
/var/log/messages or urls or whatever else you can manage to point in its direction.

One of the things I use xargs for in the course of my work is package management. My department standardized on Red Hat for all Linux boxes, which means I use RPM a lot. Sometimes, though, RPM isn't the most wonderful tool in the world to deal with. One thing that makes RPM nice, though, is that it can take flags, file arguments and options in any order (for the things I'm using
it for anyway). Let's look at an example scenario you can use even if you're not working with centralized software management in a mid-size network:

I'm a huge fan of Galeon. Back when they released 1.0.2, I had to have it. Unfortunately, my Ximian installation put packages tagged with their name on my system, and the Galeon RPM didn't recognize them, which created dependency errors. <whine> "I can't find mozilla-0.9.7"</whine>.

Having had some issues on my workstation at the office (it works fine on two other machines), I decided
to uninstall any trace of Mozilla, and get standard Mozilla packages. But I don't have a lot of time to do this stuff, so here's what I did:


$ > rpm -qa | grep mozilla | xargs -n1 -p rpm -e --nodeps

What this says in English, is "Using RPM, query all (-qa) packages, look for mozilla in the package name, and send the results one at a time (-n1), to RPM's uninstall command, and I don't care about dependencies, thank you very much
("rpm -e --nodeps"). Also, in case there's something that contains the word "mozilla" that I DON'T want erased, prompt me (-p) before uninstalling."

The above command saves you from having to manually list the packages containing the string "mozilla," then manually running separate "rpm -e" commands against them one at a time.

How about something REALLY useful! I rip CDs constantly using grip. Inevitably, I'll reinstall and forget to not format the /mp3 partition, or I'll upgrade grip and forget to change the directories it uses to store stuff...
whatever. Eventually, I have MP3s all over my hard drive. What I do then is this:


$ > find / -name *.mp3 -type f -print | xargs tar -cvzf mp3z.tar.gz

This finds all the mp3z on my entire drive and puts 'em all in a tar file, and then I can untar them wherever I want :) I actually could've piped that xargs "tar" line into a "tar xvzf" line to automatically untar them. I also could've
left out the "-type f" if I had grip set up to use a custom directory structure
that I wanted to preserve. You get the idea :) PS - this works for other types of files, too, like finding all the files that belong to you, tarring them and sending the tar to a backup somewhere, so it does have legitimate use.

Ok, so this is good for stuff that takes the file name or other argument as the last thing on the line - but what about things like "cp," that take an argument, and then another piece of input like a directory to copy to or a file to copy over or something? That's where the '-i' flag comes in. This flag allows you to specify some string that will then be replaced with the arguments you send to xargs in place. Expanding on the "cp" example:


$> ls *.mp3 | xargs -n1 -i cp {} backup/.

This command takes all of the MP3 files in the current directory, and feeds them one at a time (-n1) to the cp command, where the file argument coming in from ls will replace the curly braces. Notice I didn't specify a string with
"-i." I don't think I've ever had to. The default string that xargs will look to replace when using the -i flag is the curly braces.

As your command lines get a little more complex, or you start using xargs in scripts, there are a couple of useful troubleshooting flags you may find helpful if you run into issues. One, the -p flag, will prompt you for a yes or no before executing a command on anything. The other, which is a real life saver, is "-t," and it does NOT prompt you for a yes or no (unless you use it
with -p), but it will output the command it's trying to execute, so if
something isn't quite right, you'll be able to spot it right away.

Click Here!