Remove all files/directories except for one file

I have a directory containing a large number of files. I want to delete all files except for file.txt . How do I do this?

There are too many files to remove the unwanted ones individually and their names are too diverse to use * to remove them all except this one file.

Someone suggested using

rm !(file.txt)

But it doesn’t work. It returns:

Badly placed ()'s 

My OS is Scientific Linux 6.

Any ideas?

Asked By: Kantura



find . ! -name 'file.txt' -type f -exec rm -f {} +

will remove all regular files (recursively, including hidden ones) except any files called file.txt. To remove directories, change -type f to -type d and add -r option to rm.

In bash, to use rm -- !(file.txt), you must enable extglob:

$ shopt -s extglob 
$ rm -- !(file.txt)

(or calling bash -O extglob)

Note that extglob only works in bash and Korn shell family. And using rm -- !(file.txt) can cause an Argument list too long error.

In zsh, you can use ^ to negate pattern with extendedglob enabled:

$ setopt extendedglob
$ rm -- ^file.txt

or using the same syntax with ksh and bash with options ksh_glob and no_bare_glob_qual enabled.

Answered By: cuonglm

On my Scientific Linux 6 OS this works:

shopt -s extglob
rm !(file.txt)

I also have Debian 32bit installed on a Virtual Machine. The above does not work but the following does:

find . -type f ! -name 'file.txt' -delete
Answered By: Kantura

Maintain a copy, delete everything, restore copy:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)

In one line:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

But that requires a shell that supports here-strings.

Answered By: mikeserv

you’re all overthinking this.

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/


EDIT Actually, easier:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/
Answered By: Shadur

Another take in a different direction (iff there are no spaces in file names)

ls | grep -xv "file.txt" | xargs rm

or (works even if there are spaces in file names)

ls | grep -xv "file.txt" | parallel rm

from man grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)

 -x, --line-regexp
          Select  only  those  matches  that exactly match the
          whole line.  For a regular expression pattern,  this
          is   like   parenthesizing   the  pattern  and  then
          surrounding it with ^ and $.

Without the -x we’d keep my-file.txt as well.

Answered By: Sebastian

Use rm !("file.txt") instead of rm !(file.txt)

Answered By:

Just to give a different answer, you can use the default behavior of rm that it won’t delete folders:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir
Answered By: Nithin

I find that this approach is very simple, works, and doesn’t require any special extensions (that I know of!)

ls --hide=file.txt | xargs -d 'n' rm
Answered By: 2-bits
Categories: Answers Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.