6

I have a directory with files of many extensions in it. I would like to recursively delete *.srt files (and *.srt files only) which don't end with -en.srt (where srt is an extension). I've come up with the following solution and it seems to work fine, however, I'd like to know whether it is 100% correct.

find . -name "*.srt" ! -name "*-en.srt" -type f -exec rm -rf {} \;
8

! -- First read the answer completely then use it if you like it -- !

Your command is correct, however there is no need to use -rf as rm parameters. because you are removing files and not directories.

Another clear way to write it is (it's almost same as your command):

find -name '*.srt' -and -not -name '*-en.srt' -type f -exec rm '{}' \;

or as @steeldriver suggested you can use:

find -name '*.srt' -and -not -name '*-en.srt' -type f -ok rm '{}' \;

It will ask for your permission to remove each founded file.

You can also use -delete instead of rm {} \; however be aware of its dangers:

Don't forget that the find command line is evaluated as an expres‐ sion, so putting -delete first will make find try to delete everything below the starting points you specified. When testing a find command line that you later intend to use with -delete, you should explicitly specify -depth in order to avoid later surprises. Because -delete implies -depth, you cannot usefully use -prune and -delete together.


It is always a good idea to test what is going to happen before doing the actual job, so I suggest running:

find -name '*.srt' -and -not -name '*-en.srt' -type f | grep -i en.srt

If it return nothing then the actual command will work without any problem and you are good to go... or even:

find -name '*.srt' -and -not -name '*-en.srt' -type f | less

to check what's going to be removed.

And do not forget to quote '{}':

(when find is being invoked from a shell) it should be quoted (for example, '{}') to protect it from interpretation by shells.

  • How about -en.srt in my original command? Is it going ot be found in any place in the filename or only at the end? – menteith Aug 11 '18 at 14:08
  • @menteith At the end of file name... – Ravexina Aug 11 '18 at 14:11
  • 1
    +1 for mentioning that -rf is not needed. The part -exec rm {} \; can be improved by writing -exec rm {} + instead. This way rm will be called with as many files as fit into the command line, effectively speeding up the whole process a lot when there are many files. – PerlDuck Aug 11 '18 at 14:45
  • 2
    +1 for sharing a "good idea". Is it advisable to single quote the curly brackets ('{}') to prevent the shell from expanding strange filenames? – mook765 Aug 11 '18 at 15:27
  • 1
    @dessert, -delete usage has been suggested in answer... and about -name option you are right` it's my bad habit to always use -iname instead of -name... will update it. – Ravexina Aug 12 '18 at 7:45
4

Let’s do it solely with bash globbing: With the extglob and globstar options enabled,

rm **/!(*-en).srt

deletes every file ending in .srt excluding anything ending in -en.srt from the current as well as any subdirectory.
If you‘re not sure about an expansion like this, test by prepending echo (see example below).

Example

$ tree
.
├── 01.srt
├── 02.srt
├── no-en.srt
├── not-en.srt
├── subdir
│   ├── 01.srt
│   ├── 02.srt
│   ├── no-en.srt
│   └── not-en.srt
└── unrelated.png
$ shopt -s extglob globstar
$ echo rm **/!(*-en).srt
rm 01.srt 02.srt subdir/01.srt subdir/02.srt
$ rm **/!(*-en).srt
$ tree
.
├── no-en.srt
├── not-en.srt
├── subdir
│   ├── no-en.srt
│   └── not-en.srt
└── unrelated.png

Explanations

  • **/ – with the globstar option enabled this matches any number of directories and subdirectories
  • !(*-en) – with the extglob option enabled this matches anything except the given pattern, so anything not ending in -en

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.