Remove all files except some from a directory

BashRm

Bash Problem Overview


When using sudo rm -r, how can I delete all files, with the exception of the following:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

Bash Solutions


Solution 1 - Bash

find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

If you don't specify -type f find will also list directories, which you may not want.


Or a more general solution using the very useful combination find | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

for example, delete all non txt-files in the current directory:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

The print0 and -0 combination is needed if there are spaces in any of the filenames that should be deleted.

Solution 2 - Bash

rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

The extglob (Extended Pattern Matching) needs to be enabled in BASH (if it's not enabled):

shopt -s extglob

Solution 3 - Bash

find . | grep -v "excluded files criteria" | xargs rm

This will list all files in current directory, then list all those that don't match your criteria (beware of it matching directory names) and then remove them.

Update: based on your edit, if you really want to delete everything from current directory except files you listed, this can be used:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

It will create a backup directory /tmp_backup (you've got root privileges, right?), move files you listed to that directory, delete recursively everything in current directory (you know that you're in the right directory, do you?), move back to current directory everything from /tmp_backup and finally, delete /tmp_backup.

I choose the backup directory to be in root, because if you're trying to delete everything recursively from root, your system will have big problems.

Surely there are more elegant ways to do this, but this one is pretty straightforward.

Solution 4 - Bash

I prefer to use sub query list:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

> -v, --invert-match select non-matching lines > > \| Separator

Solution 5 - Bash

Assuming that files with those names exist in multiple places in the directory tree and you want to preserve all of them:

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete

Solution 6 - Bash

You can use GLOBIGNORE environment variable in Bash.

Suppose you want to delete all files except php and sql, then you can do the following -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

Setting GLOBIGNORE like this ignores php and sql from wildcards used like "ls *" or "rm *". So, using "rm *" after setting the variable will delete only txt and tar.gz file.

Solution 7 - Bash

Since nobody mentioned it:

  • copy the files you don't want to delete in a safe place
  • delete all the files
  • move the copied files back in place

Solution 8 - Bash

You can write a for loop for this... %)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

Solution 9 - Bash

A little late for the OP, but hopefully useful for anyone who gets here much later by google...

I found the answer by @awi and comment on -delete by @Jamie Bullock really useful. A simple utility so you can do this in different directories ignoring different file names/types each time with minimal typing:

rm_except (or whatever you want to name it)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

e.g. to delete everything except for text files and foo.bar:

rm_except *.txt foo.bar 

Similar to @mishunika, but without the if clause.

Solution 10 - Bash

If you're using zsh which I highly recommend.

rm -rf ^file/folder pattern to avoid

With extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

Solution 11 - Bash

Trying it worked with:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

but names with spaces are (as always) tough. Tried also with Virtualbox\ VMs instead the quotes. It deletes always that directory (Virtualbox VMs).

Solution 12 - Bash

Just:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

Or:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

Solution 13 - Bash

Make the files immutable. Not even root will be allowed to delete them.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

All other files have been deleted.
Eventually you can reset them mutable.

chattr -i *

Solution 14 - Bash

I belive you can use

rm -v !(filename)

Except for the filename all the other files will e deleted in the directory and make sure you are using it in

Solution 15 - Bash

This is similar to the comment from @siwei-shen but you need the -o flag to do multiple patterns. The -o flag stands for 'or'

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm

Solution 16 - Bash

You can do this with two command sequences. First define an array with the name of the files you do not want to exclude:

files=( backup.tar.gz script.php database.sql info.txt )

After that, loop through all files in the directory you want to exclude, checking if the filename is in the array you don't want to exclude; if its not then delete the file.

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

Solution 17 - Bash

The answer I was looking for was to run script, but I wanted to avoid deleting the sript itself. So incase someone is looking for a similar answer, do the following.

Create a .sh file and write the following code:

    cp my_run_build.sh ../../ 
    rm -rf * cp  
    ../../my_run_build.sh . 
    /*amend rest of the script*/

Solution 18 - Bash

Since no one yet mentioned this, in one particular case:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(or just rm $OLD_FILES)

or

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

You may need to use shopt -s nullglob if some files may be either there or not there:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

without nullglob, echo *.sh *.bash may give you "a.sh b.sh *.bash".

(Having said all that, I myself prefer this answer, even though it does not work in OSX)

Solution 19 - Bash

Rather than going for a direct command, please move required files to temp dir outside current dir. Then delete all files using rm * or rm -r *.

Then move required files to current dir.

Solution 20 - Bash

Remove everything exclude file.name:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmasjokoView Question on Stackoverflow
Solution 1 - BashawiView Answer on Stackoverflow
Solution 2 - Bashpl1nkView Answer on Stackoverflow
Solution 3 - BashdariooView Answer on Stackoverflow
Solution 4 - BashNick TsaiView Answer on Stackoverflow
Solution 5 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 6 - BashtheharshestView Answer on Stackoverflow
Solution 7 - Bashgniourf_gniourfView Answer on Stackoverflow
Solution 8 - BashmishunikaView Answer on Stackoverflow
Solution 9 - BashlhuberView Answer on Stackoverflow
Solution 10 - Bashsudo bangbangView Answer on Stackoverflow
Solution 11 - BashjuanfalView Answer on Stackoverflow
Solution 12 - BashwyxView Answer on Stackoverflow
Solution 13 - BashL'alligator des abersView Answer on Stackoverflow
Solution 14 - BashGowtam ThakurView Answer on Stackoverflow
Solution 15 - BashDaniel ChenView Answer on Stackoverflow
Solution 16 - BashLeonardo HermosoView Answer on Stackoverflow
Solution 17 - BashEpscillon RulesView Answer on Stackoverflow
Solution 18 - Bash18446744073709551615View Answer on Stackoverflow
Solution 19 - BashAjeeshView Answer on Stackoverflow
Solution 20 - Bashmik-makView Answer on Stackoverflow