POSIX and xargs

nicholas on 2009-06-08T09:30:58

Dear POSIX,

Why did you decide that xargs with no filename arguments should run the command once? I can only assume that there are zero mathematicians and zero computer scientists on the relevant committee. How else could such a demented special case get through?


Either Way Can Be Wrong

Smylers on 2009-06-08T10:37:00

I used to think that as well (though I'm not sure Posix are necessarily at fault: possibly they just codified what was already a de facto standard).

Then I encountered a situation where I did need the command to run once, even with no arguments. In normal circumstances* the command runs exactly once regardless of the number of arguments, not once per argument, so there's consistency in making this always be once, even with no arguments.

Whichever way they picked was going to be wrong sometimes. What they really should've done was spec an option for picking the ‘other’ behaviour. I'm still inclined to think they picked the wrong default, but so long as I could get both I'm not that bothered.

Gnu's xargs has the -r option, which does what you want. FreeBSD's (and therefore presumably OS X's) doesn't have this option.**

Frustratingly I can't now recall the circumstances in which I wanted the ‘run once anyway’ behaviour; if I remember I'll post a follow-up, since I realize this is much less persuasive without it!

* Non-normal circumstances include having so much input it needs to be split into multiple invocations of the command, or using -n 1 to run the command once per argument.

** FreeBSD's does however have the useful -o option, handy for opening a bunch of files in Vim, which Gnu's is missing.

There is worse precedent

Aristotle on 2009-06-08T15:51:22

Most shells will invoke foo and pass a literal bar.* as the first argument if you run foo bar.* if nothing in the current directory matches bar.*. In bash since 2.something you can shopt -s failglob to prevent this.

But then the shell will also refuse to let you run foo bar.* baz.* if either bar.* or baz.* fail, when really you probably only wanted it to refuse if both fail. So basically you want the behaviour of shopt -s nullglob when there’s more than one glob.

Or at least, you want that behaviour most of the time.

Defaults: It’s Tricky To Get Them Right.

A LiveJournal reply

pne on 2009-06-10T16:01:54

There's another reply to this journal entry over here.