I find that using an idiom like
find foo -maxdepth 1 -print0 | xargs -0 -J % mv % bar/
is so useful. It replaces the
replstr (“%” in this example) with all the arguments at once, or as many as can fit without going over the system’s limit. I couldn’t believe it when I learned that the GNU version of xargs lacks this flag. Yes, it’s only on the BSD xargs as far as I can tell.
Every time I’ve searched, someone suggests using the
-I flag on GNU xargs instead, but they are not quite the same. The
-I flag substitutes the
replstr one argument at a time, so that in the earlier example, instead of executing
mv foo/1 foo/2 foo/3 bar/
only once, with the
-I flag it will instead do
mv foo/1 bar/
mv foo/2 bar/
mv foo/3 bar/
I’ve also tried using the
-L flags, but they are mutually exclusive with each other and with
-I. OK, so we need some kind of klugey workaround.
find foo -type f -print0 | cat - < (echo bar/) | xargs -0 -p mv
This adds the “bar/” suffix to the standard input before adding it to the end of the
mv command. “But,” you say, “those strings are supposed to be null-terminated!” True, but we’re providing a suffix rather than an extra replacement argument, so the EOF signaled from the input stream is really all we need.
There’s another, more intuitive way, but harder to get right; get the argument list output from a subshell command:
mv $(find foo -type f) bar/
But this suffers from not handling weird file names the right way. Instead one could do:
echo mv $(/bin/ls --quoting-style=escape foo) bar/
This actually works better for file names, but lacks the flexibility of
Is this stuff really what we ought to do? Just give us the -J, GNU. If you know a different way to deal with this, tweet me @realgeek and I’ll update this post.