3

This site presents the xargs command with a -J option making able to pass the standard input into a desired position at the command argument:

find . -name '*.ext' -print0 | xargs -J % -0 rsync -aP % user@host:dir/

but at a GNU xargs man page this option is not present.

Which is the way to do this on, for commands accepting this?

3

I am not sure this is what you were expecting, but in the BSD world (such as macOS) -I and -J differ in how they pass the multiple "lines" to the command. Example:

$ ls
file1 file2 file3

$ find . -type f -print0 | xargs -I % rm %
rm file1
rm file2
rm file3

$ find . -type f -print0 | xargs -J % rm %
rm file1 file2 file3

So with -I, xargs will run the command for each element passed to it individually. With -J, xargs will execute the command once and concatenate all the elements and pass them as arguments all together.

Some commands such as rm or mkdir can take multiple arguments and act on them the same way as if you passed a single argument and ran them multiple times. But some apps may change depending how you pass arguments to them. For instance the tar. You may create a tar file and then add files to it or you may create a tar file by adding all the files to it in one go.

$ find . -iname "*.txt" -or -iname "*.pdf" -print0 | xargs -0 -J % tar cjvf documents.tar.bz2 %
1

If this is the -J flag for the BSD version of xargs I don't believe there's an exact equivalent option for GNU xargs. -J replaces a single occurrence of replstr (e.g. %) with each line coming in through standard input. The GNU version has a similar option, though: -I. However, you can use replstr multiple times with that flag.

For simple use cases like your example you should be able to use GNU xargs -I as a drop-in replacement...

find . -name '*.ext' -print0 | xargs -I % -0 rsync -aP % user@host:dir/

(Further confusing things is that the BSD version also has -I and it's similar in function to both -J and GNU -I! But this -I is affected by other flags and is probably not what you are looking for.)

  • I am confused, i understood that the -I % is for executing the command for every line printed in the previous piped command; 10 lines, 10 executions. and that the -J % "would" replace the whole list of lines, just when we do xargs ls -tr replacing the whole list at the end. I am actually seeking for the second interpretation – Brethlosze Nov 29 '17 at 13:26
  • I actually dont care to stick with xargs, i would like to know a way to pass the previous command into the next one into a given position, like rsync -aP (find . -name '*.ext' -print0) user@host:dir/ but i dont know if this notation is valid (i am assuming no whitespaces, which i will solve properly) – Brethlosze Nov 29 '17 at 13:34
  • Sounds like you're talking about command substitution: rsync -aP $(find . -name '*.ext' -print0) ...etc. But you don't want to do that it's not correct...it will break much of the time because of the shell's word splitting and expansions. You're better off using xargs like you are or you can look at find's -exec/-execdir flag (in particular the second form with + modifier). – B Layer Nov 29 '17 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.