gnu - xargs process string as multiple arguments

07
2014-07
  • Pete

    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 ....'

  • Answers
  • Ole Tange

    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.


  • Related Question

    command line - find: -exec vs xargs (aka Why does "find | xargs basename" break?)
  • quack quixote

    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?


  • Related Answers
  • akira

    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).
    
  • perlguy9

    Try this:

    find . -name '*.deb' | xargs -n1 basename
    
  • John T

    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.