Remove all files/directories except for one file
POSIXly:
find . ! -name 'file.txt' -type f -exec rm -f {} +
will remove all regular files (recursively, including hidden ones) except 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.
Another take in a different direction (iff there are no spaces in file names)
ls | grep -v file.txt | xargs rm
or (works even if there are spaces in file names)
ls | grep -v 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)
Maintain a copy, delete everything, restore copy:
{ rm -rf *
tar -x
} <<TAR
$(tar -c $one_file)
TAR
In one line:
{ rm -rf *; tar -x; } <<< $(tar -c $one_file)
But that requires a shell that supports here-strings.