Search code examples
linuxbashshellubuntu-14.04linux-mint

Using "find … -delete" to remove image files only from special subdirectories


I need to clean up some subdirectories inside my music collection from unwanted images. I’m using Ubuntu 14.04 and/or Linux Mint 17.2 and a bash shell script using the find command.

The directory structure (minimal example) is as follows:

Tagged
  Artist #1
    Artist #1 - An Album
      Artist #1 - A Track.flac
      cover.jpg
      something.png
    Artist #1 - [compilations]
      Artist #1 - A Track.flac
      cover.jpg
      something.png
  Artist #2
    Artist #2 - Another Album
      Artist #2 - A Track.mp3
      cover.jpg

Only in the subfolders ending with "[compilations]", I want to delete all kind of jpeg and/or png images (because the tagging software erroneously puts them there). Any images that happen to be in normal "album" folders I wish too keep.

With my directory structure, folders with "[compilations]" in the name can only happen just below the "Artist" folders, repectively; so a maximum of two levels deep.

I came up with the following find command:

$ cd Tagged
$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' -delete \;

This seems to do something and takes a while, but the files "./Artist #1/Artist #1 - [compilations]/cover.jpg" and "./Artist #1/Artist #1 - [compilations]/something.png" are still there (and all other image files).

Being quite new to Linux, I assume I make a dumb mistake using find's -delete option, because the following command (without -delete) shows the files correctly:

$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' \;
./Artist #1/Artist #1 - [compilations]/cover.jpg
./Artist #1/Artist #1 - [compilations]/something.png

So here are my questions:

  • Why does the -delete not work?
  • Is this command really safe regarding "extravaganza" like whitespace, glob characters and foreign characters in the paths and filenames?
  • How would I have to rewrite the above command, still using bash and find?
  • Could the command be optimized (re speed, safety, nested finds)?

In the actual collection, the command must traverse 16899 folders, almost all of them contain whitespace and foreign characters (like Czech, Russian, Japanese, Greek, German …), so it must be robust.

Thanks in advance for any insights and some enlightenment!


Solution

  • Your -delete predicate only applies to the

    -iname '*.png'
    

    predicate, because you missed groupings: when you give find the following:

    -type f -iname '*.jp*g' -or -iname '*.png' -delete
    

    because of the precedence of the boolean operators, find understands:

    \( -type f -iname '*.jp*g' \) -or \( -iname '*.png' -delete \)
    

    To fix this, use:

    -type f \( -iname '*.jp*g' -or -iname '*.png' \) -delete
    

    I'd suggest that to experiment you replace -delete with -print: you'll see what the -delete applies to!

    Now, regarding your nested find: because of the structure of your directory tree (your files are only in depth 3), you should be able to do with only one instance of find:

    find -maxdepth 3 -path '*/*\[compilations\]/*' \( -iname '*.jp*g' -o -iname '*.png' \) -type f -print
    

    (I put -print instead of -delete so that you can check the command before executing it with -delete).