tags:

views:

426

answers:

3

I want to understand the use of xargs man in Rampion's code:

screen -t man /bin/sh -c 'xargs man || read'

Thanks to Rampion: we do not need cat!

Why do we need xargs in the command?

I understand the xargs -part as follows

  1. cat nothing to xargs
  2. xargs makes a list of man -commands

I have had an idea that xargs makes a list of commands. For instance,

find . -type f -print0 | xargs -0 grep masi

is the same as a list of commands:

find fileA AND grep masi in it 
find fileB AND grep masi in it 
           and so on for fileC, fileD, ...
+4  A: 

No, I don't cat nothing. I cat whatever input I get after I run the command. cat is actually extraneous here, so let's ignore it.

xargs man waits on user input. Which is necessary. Since in the script you grabbed that from, I can't paste in the argument for man until after I create the window. So the command that runs in the window needs to wait for me to give it something, before it tries to run man.

If we just ran screen /bin/sh -d 'man || read', it would always complain "What manual page do you want?" since we never told it.

rampion
+2  A: 

xargs gathers arguments from stdin and executes the command given with those arguments.

so cat is waiting for something to be typed, and then xargs is running man with that input.

xargs is useful if you have a lot of files to process, I often use it with output from find. xargs will stuff as many arguments as it can onto the command line.
It's great for doing something like

find . -name '*.o' -print | xargs rm
Charlie
+3  A: 

The cat command does not operate on nothing; it operates on standard input, up until it is told that the input is ended. As Rampion notes, the cat command is not necessary here, but it is operating on its implicit input (standard input), not on nothing.

The xargs command reads the output from cat, and groups the information into arguments to the man command specified as its (only) argument. When it reaches a limit (configurable on the command line), it will execute the man command.

The find ... -print0 | xargs -0 ... idiom deals with file names that contain awkward characters such as blanks, tabs and newlines. The find command prints each filename followed by an ASCII NUL ('\0'); this is one of two characters that cannot appear in a simple file name - the other being '/' (which appears in path names, of course, but not in simple file names). It is not directly equivalent to the sequence you provide; xargs groups collections of file names into a single argument list, up to a size limit. If the names are short enough (they usually are), then there will be fewer executions of grep than there are file names.

Note, too, the grep only prints the file name where the material is found if it has more than one file to search -- or if it supports an option so that it always prints the file names and the option is used: '-H' is a GNU extension to grep that does this. The portable way to ensure that the file names always appear is to list /dev/null as the first file (so 'xargs grep something /dev/null'); it doesn't take long to search /dev/null.

Jonathan Leffler
Thank you for your answer! So `\0 and /` cannot be in filenames. `xargs` has rather an impractical limit. There are variants of `grep` such as GNU grep. --- **Do you mean that xargs has /dev/null as the first file?** Do you mean that some variants of `xargs` need /dev/null as the first argument?
Masi
It's not an impractical limit at all, Masi. In fact, it's eminently practical. As for /dev/null, he means to specify that as a hard-coded first file-name parameter to grep: `xargs -0 grep masi /dev/null`. Xargs will put additional file names after that. Since grep has been given multiple names, it will print the file names whenever it finds a match, which it doesn't do when its command line contains just one file name. More direct than the /dev/null trick is to use grep's `-H` option.
Rob Kennedy
I opened a new thread based on Rob's comment at http://stackoverflow.com/questions/1122218/to-understand-greps-option-h
Masi