Search code examples
linuxxargs

How do I combine -I and -n with xargs?


I want to move a large set of files using find and xargs. Normally I'd do this:

find /foo -name 'bar*' | tr '\n' ' ' | xargs -I % echo mv % /dest

However, when there are too many files to move, I hit the limit of the number of arguments to pass to mv. xargs has a -n which seems like it would be perfect for this:

$ echo {0..9} | xargs -n 3 echo
0 1 2
3 4 5
6 7 8
9

However, -I implies -L 1, so I can't use -I with -n:

$ echo {0..9} | xargs -n 3 -I % echo % /dest
0 1 2 3 4 5 6 7 8 9 /dest

I was hoping for behaviour like this:

$ echo {0..9} | xargs -n 3 -I % echo % /dest
0 1 2 /dest
3 4 5 /dest
6 7 8 /dest
9 /dest

Is this possible with xargs? I don't have GNU Parallel on my machines.


Solution

  • The mv command (at least from Linux coreutils) has the convenient -t flag that perfectly matches this use case:

    find /foo -name 'bar*' | tr '\n' ' ' | xargs mv -t /dest
    

    Above also supports keeping any weirdo filename without filename massaging:

    find /foo -name 'bar*' -print0 | xargs -0 mv -t /dest
    

    If for whatever reason you want to use mv as usual, below could also work (i.e. use a sh scriptlet to "consume" all arguments ($@)):

    find /foo -name 'bar*' | tr '\n' ' ' | xargs sh -c 'mv "$@" /dest' --