gnu - xargs process string as multiple arguments
2014-07
Linux GNU xargs
I have the file doit with
arg1 arg2 arg3 arg4
arg1 arg2 arg3 arg4
I want to perform
command arg1 arg2 arg3 arg4
command arg2 arg2 arg3 arg4
What I can't figure out is how to do this with xargs
If one does xargs -a doit -I % command %
It runs
command 'arg1 arg2 arg3 arg4'
i.e run command with the first argument = 'arg1 arg2 ....'
If you use GNU Parallel you can do:
parallel -a doit eval command
or:
parallel -a doit --colsep ' ' command
To learn more: Watch the intro video for a quick introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 and walk through the tutorial (man parallel_tutorial). You command line with love you for it.
I was trying to find all files of a certain type spread out in subdirectories, and for my purposes I only needed the filename. I tried stripping out the path component via basename
, but it did't work with xargs
:
$ find . -name '*.deb' -print | xargs basename
basename: extra operand `./pool/main/a/aalib/libaa1_1.4p5-37+b1_i386.deb'
Try `basename --help' for more information.
I get the same thing (exactly the same error) with either of these variations:
$ find . -name '*.deb' -print0 | xargs -0 basename
$ find . -name '*.deb' -print | xargs basename {}
This, on the other hand, works as expected:
$ find . -name '*.deb' -exec basename {} \;
foo
bar
baz
This happens on up-to-date Cygwin and Debian 5.0.3. My diagnosis is that xargs is for some reason passing two input lines to basename, but why? What's going on here?
because basename
wants just one parameter... not LOTS of. and xargs
creates lots parameters.
to solve your real problem (only list the filenames):
find . -name '*.deb' -printf "%f\n"
which prints just the 'basename' (man find):
%f File's name with any leading directories
removed (only the last element).
Try this:
find . -name '*.deb' | xargs -n1 basename
basename only accepts a single argument. Using -exec
works properly because each {}
is replaced by the current filename being processed, and the command is run once per matched file, instead of trying to send all of the arguments to basename in one go.