Delete files not matching pattern using xargs

The following command is from https://www.tecmint.com/xargs-command-examples/ the example #9. It is to delete files not matching *gz from current directory.

$ find . -type f -not -name '*gz' -print0 | xargs -0 -I {} rm -v {}

What are the purpose of -print0 arg of find command and -0 and -I {} args of xargs command? Why are they needed? Thanks!


-print0 tells find to output its results separated by null bytes instead of the usual newline characters. This is necessary if the filenames do (or may in the future) contain newline characters themselves.

You then need to tell xargs to expect null-delimited data coming down the pipe - that's what the -0 is for. So it's necessary here when using -print0 on the LHS.

Meanwhile {} is a replacement string - when you use -I {}, each {} in the following command will be replaced by an input item. It's only really necessary when you need control over where the item appears in the following command line (and has the side-effect of running a single invocation for each item, equivalent to adding -L 1). IMHO it's not necessary here, and makes the solution inefficient since it runs rm once for each file found, instead of in batches.

Note that find has a -exec option and a -delete option that both avoid the issue of writing / reading delimited data altogether:

find . -type f -not -name '*gz' -exec rm -v {} +

or

find . -type f -not -name '*gz' -print -delete

(the -print here to give similar functionality as the -v option to rm).