4

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

2 Answers 2

5

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

8
  • I'm eager to find out wheter OP's version of find supports !. I kind of assumed it's not since -not was not supported. Mar 14, 2016 at 11:53
  • 1
    @DmitryGrigoryev, hardly any find implementation supports -not (an extension added to GNU find in 2.0 in 1990, sometimes added later to other implementations like FreeBSD in 2002 for compatibility with GNU find). They all support ! though and have had since the very first version of Unix in 1970. Mar 14, 2016 at 12:25
  • 1
    @DmitryGrigoryev (continued) what the OP's find might miss is support for -exec {} + which was added recently to busybox find. Mar 14, 2016 at 12:27
  • @DmitryGrigoryev, actually the early Unix find implementations didn't take any option, all the -name, !... were added later on in the 70s. Mar 14, 2016 at 12:43
  • It should have been hard to use it then, considering one couldn't post-process the output. Mar 14, 2016 at 13:17
1

Busybox find claims to support -regex option, which you could use to remove files which do match the pattern:

find . -type f -regex '.*\.tmp\|.*\.core' -delete

Unfortunately, excluding a list of extensions without the -not option is not possible in the general case (technically, there is a solution, but it doesn't scale). That's the reason to include the -not option in the first place. If you need to exclude an arbitrary list of extensions, you'll need a find which supports this option, or find+grep+xargs:

find . | grep -v -e '\.jpg$' -e '\.txt$' | xargs rm
1
  • 2
    You can't post-process the output of find . unless you can make some assumptions on what characters the filename may contain. It's even worse when piping to xargs as in addition to newline, you'd also have problems with blanks, quotes and backslashes. Mar 14, 2016 at 11:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .