Here's the simple solution you should probably use:
mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif
There's nothing special about the .keep
extension, this just makes it so that the filename temporarily doesn't end in .gif
.
If you must not rename the file (and there are scripting situations where this is important):
for X in *.gif; do
if [ "$X" != "filename.gif" ]; then
rm "$X"
fi
done
Or you can write it shorter like this:
for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done
You may prefer to use find
instead; it's very powerful, you might consider it more readable, and it better handles weird filenames with characters like *
in them.
find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete
I've used the -not
operator for readability, but if POSIX compliance is important--if you're not using GNU find, or if this is for a script you intend to redistribute to others or run on a variety of systems--you should use the !
operator instead:
find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete
One handy thing about find
is that you can easily modify the command for case-insensitivity, so that it finds and deletes files with extensions like .GIF
too:
find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete
Please note that I've used -iname
in place of -name
for the search pattern *.gif
but I have not used it for filename.gif
. Presumably you know exactly what your file is called, and -iname
will match alternate capitalization not just in the extension, but anywhere in the filename.
All these solutions only delete files residing immediately in the current directory. They don't delete files not contained in the current directory, and they don't delete files that reside in subdirectories of the current directory.
If you want to delete files everywhere contained within the current directory (that is, including in subdirectories, and in subdirectories of those subdirectories, and so forth--files contained within the current directory or any of its descendants), use find
without maxdepth -1
:
find . -not -name 'filename.gif' -name '*.gif' -delete
Be careful with this!
You can also set other values with -maxdepth
. For example, to delete files in the current directory and its children and grandchildren but not any deeper:
find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete
Just make sure you never put -delete
first, before the other expressions! You'll see I've always put -delete
at the end. If you put it at the beginning, it would be evaluated first, and all the files under .
(including files not ending in .gif
and files in deep sub-sub-sub...directories of .
) would be deleted!
For more information, see the manual pages for bash
and sh
and for the commands used in these examples: mv
, rm
, [
, and (especially) find
.
! -- 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.
Best Answer
That requires conditions joined by logical OR instead of the default logical AND (parentheses are required because OR has lower precedence than AND, and they must be escaped or quoted so that the shell passes them to
find
as literals):Change
-print
to-delete
once you are certain that it's doing the right thing. In the GNU implementation offind
, you may use-or
in place of-o
if you prefer.