Find Busybox – How to Delete or Keep Certain File Extensions

busyboxfind

I have a folder which contains files (various file extensions) and subfolders. I want to keep certain file extensions and delete the rest.

e.g. keep all .txt and .jpg files and delete all other files.

on regular UNIX/GNU, I can use find together with the "-not" parameter to achieve this.

> find . -not -name "*.jpg" -not -name "*txt" -type f -delete

But sadly, this parameter is not available on busybox find.

Any ideas on how it can be done? Thanks a lot

Best Answer

-not and -delete are non-standard extensions.

There's no reason why you'd want to use -not, when there's a shorter standard equivalent: !.

For -delete, you'll have to invoke rm with the -exec predicate:

find . ! -name '*.jpg' ! -name '*.txt' -type f -exec rm -f '{}' +

(if you have an older version of busybox, you may need the -exec rm -f '{}' ';' which runs one rm per file).

That command above is standard, so will work not only in busybox but also with other non-GNU modern implementations of find.

Note that on GNU systems at least, that command (with any find implementation as long as it uses GNU fnmatch(3)) may still remove some files whose name ends in .jpg or .txt, as the *.jpg pattern would fail to match files whose name contains invalid characters in the current locale.

To work around that, you'd need:

LC_ALL=C find . ! -name '*.jpg' ! -name '*.txt' -type f -exec rm -f '{}' +

Also note that contrary to GNU's -delete, that approach won't work in very deep directory trees as you would then end up reaching the maximum size of a file path passed to the unlink() system call. AFAIK, with find, there's no way around that if your find implementation doesn't support -execdir nor -delete.

You may also want to read the security considerations discussed in the GNU find manual if you're going to run that command in a directory writable by others.

Related Question