Delete all files except files with the extension pdf in a directory

cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • The first command will take you to the directory in which you want to delete your files
  • The second command will delete all files except with those ending with .pdf in filename

For example, if there is a directory called temp in your home folder:

cd ~/temp

then delete files:

find . -type f ! -iname "*.pdf" -delete

This will delete all files except xyz.pdf.

You can combine these two commands to:

find ~/temp -type f ! -iname "*.pdf" -delete

. is the current directory. ! means to take all files except the ones with .pdf at the end. -type f selects only files, not directories. -delete means to delete it.

NOTE: this command will delete all files (except pdf files but including hidden files) in current directory as well as in all sub-directories. ! must come before -name. simply -name will include only .pdf, while -iname will include both .pdf and .PDF

To delete only in current directory and not in sub-directories add -maxdepth 1:

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete

With bash's extended shell globbing, you could remove any files with extensions other than .pdf using

rm -- *.!(pdf)

As noted by @pts, the -- characters indicate the end of any command options, make the command safe in the rare case of files whose names start with a - character.

If you want to delete files without any extension as well as those with extensions other than .pdf, then as pointed out by @DennisWilliamson you could use

rm -- !(*.pdf)

Extended globbing should be enabled by default, but if not you can do so using

shopt -s extglob

Especially if you intend to use this inside a script, it's important to note that if the expression doesn't match anything (i.e. if there are no non-pdf files in the directory), then by default the glob will be passed unexpanded to the rm command, resulting in an error like

rm: cannot remove `*.!(pdf)': No such file or directory

You can modify this default behaviour using the nullglob shell option, however that has its own issue. For a more thorough discussion see NullGlob - Greg's Wiki


Delete to trash:

$ cd <the directory you want>
$ gvfs-trash !(*.pdf)

Or via mv command (but in this way you cannot restore it from Trash since it doesn't record .trashinfo information, so this means you moved your files to a destination where it is as following).

mv !(*.pdf) ~/.local/share/Trash/files

The easiest approach: Create another directory somewhere (if you're only deleting in one directory, not recursively, it can even be a subdirectory); move all the .pdf's there; delete everything else; move the pdf's back; delete the intermediate directory.

Quick, easy, you can see exactly what you're doing. Just make sure the intermediate directory is on the same device as the directory you're cleaning up so that moves are renames, not copies!


Use bash's GLOBIGNORE:

GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE

From bash's man page:

GLOBIGNORE:

            A colon-separated list of patterns defining the set
            of filenames to be ignored by pathname expansion.

A quick test:

mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *

Output:

y.zip
z.mp3