In linux, how to delete all files EXCEPT the pattern *.txt?
I know how to delete all txt file under current directory by rm *.txt . Does anyone know how to delete all files in current directory EXCEPT txt file?
As always, test the given answers with a harmless command like ls before actually attempting to call rm .
9 Answers 9
find . -type f ! -name '*.txt' -delete
Or bash’s extended globbing features:
setopt extendedglob rm *~*.txt(.) # || ^^^ Only plain files # ||^^^^^ files ending in ".txt" # | \Except # \Everything
Some of these may need to be adapted depending on whether you have folders and what you want to do with them.
@LauriRanta depends on what’s in the folder, which we haven’t gotten an answer to. It’s fine as is if all the files have extensions, and rm would choke if there were folders.
I’ve got an issue with the brackets. When I use the globbing style in a bash script, it complains about a syntax error and the parentheses. However doing it from the CLI works.
@izogfif check this find . -type f ! -name «*.txt» | xargs -r rm would work in GNU\xargs. BSD and UNIX xargs command may not have -r you have to check your local man xargs
If you just want to delete all files except ‘*.txt’ then you can use the following command:
$ find . -type f ! -name «*.txt» -exec rm -rf <> \;
but if you also want to delete directories along with the files then you can use this:
$ find . ! -name «*.txt» -exec rm -r <> \;
there are many ways could do it. but the most simple way would be (bash):
shopt -s extglob is powerful. tecmint.com/… provides good examples. To delete all except certain extensions, rm -v !(*.zip|*.odt) works.
You can use inverted grep and xargs
@phillipsk grep -v *.txt will work only if there’s exactly one .txt file. If there is none, grep will use *.txt as the pattern; if there’s more than one, it will search for the first filename inside all of the other .txt files, ignoring the output from ls . (Exact results may depend on the shell’s glob options.)
.txt$ will match strings ending with txt regardless of the dot. Because grep takes regular expression as parameter. So files a.txt and aatxt and a-txt will all be matched by this expression. Correct expression should be ls | grep -v \\.txt$ | xargs —no-run-if-empty rm . For curious people: If you want to play around with the expression safely use this test expression ls | grep \\.txt$ | xargs —no-run-if-empty echo (note: there’s no -v flag and rm=>echo ). Note2: you may have noticed double backslash. One is for regex, another is for bash to escape slash.
In Linux terminal, how to delete all files in a directory except one or two
In a Linux terminal, how to delete all files from a folder except one or two? For example. I have 100 image files in a directory and one .txt file. I want to delete all files except that .txt file.
You’d better show some pattern of how the exceptions should look like. Otherwise we will be able just to give a very general answer.
5 Answers 5
From within the directory, list the files, filter out all not containing ‘file-to-keep’, and remove all files left on the list.
ls | grep -v 'file-to-keep' | xargs rm
To avoid issues with spaces in filenames (remember to never use spaces in filenames), use find and -0 option.
find 'path' -maxdepth 1 -not -name 'file-to-keep' -print0 | xargs -0 rm
Or mixing both, use grep option -z to manage the -print0 names from find
I tried this command as sudo ls directory/directory/directory1/ | grep -v ‘readme.txt’ | xargs rm but didn’t work. I have to run this command on many directories. Suppose I directory has siblings directory2, directory3 .
@Bilal For the command starting with ls , yes, it will do the job in the current directory. If you use the find command, then you can list as many directories as you want as ‘path’ .
In option 1, grep needs to have —line-regexp argument here, b/c otherwise /bin/w will match /bin/which .
In general, using an inverted pattern search with grep should do the job. As you didn’t define any pattern, I’d just give you a general code example:
ls -1 | grep -v 'name_of_file_to_keep.txt' | xargs rm -f
The ls -1 lists one file per line, so that grep can search line by line. grep -v is the inverted flag. So any pattern matched will NOT be deleted.
For multiple files, you may use egrep:
ls -1 | grep -E -v 'not_file1.txt|not_file2.txt' | xargs rm -f
Update after question was updated: I assume you are willing to delete all files except files in the current folder that do not end with .txt . So this should work too:
find . -maxdepth 1 -type f -not -name "*.txt" -exec rm -f <> \;
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
Thanks, and yes I was looking for a one-line solution. It’s too time consuming to keep moving files around as I have to do this quite often.
8 Answers 8
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.
Specifying the directory is good practice (fullpath in this case? or maybe add a warning here that this command deletes every file starting from the current working directory ?). I also usually write any example with rm as echo rm instead, and ask people to only take out the echo when they are really sure it will do what they want. Other than that, +1 for the thorough answer
@Meysam — see my answer for a solution that will handle a list of files. Else with Gnouc’s find solution you can do ! \( -name one_file -o -name two_file \) and so on.
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
-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.
Ciao @Matteo, it works for files with spaces too, but you need to surround the grep-pattern by quotes, e.g. ls | grep -v «a file with spaces.bin» | xargs rm . This is normal grep syntax.
@Sebastian The problem is not the grep but rm . rm will get a list of space separated arguments. Try touch ‘a b’; touch ‘c d’; ls | grep -v ‘a b’ | xargs rm : you will get rm: c: No such file or directory and rm: d: No such file or directory
It’s not only spaces, it’s all blanks and newlines, but also quoting characters (single, double quotes and backslash) and filenames starting with — .
This worked for me ls -Q | grep -v file.txt | xargs rm -fr . -Q switch is «enclose entry names in double quotes»
Maintain a copy, delete everything, restore copy:
But that requires a shell that supports here-strings.
Isn’t more efficient to move it to another directory and move it back? We don’t need to deal with the content of the file, only with its path.
@Derek — it’s really not that crazy. POSIX requires that a shell redirect its input to the command you specify when it encounters a here-document. The command-substitution has to complete before anything else happens. Most shells use temp-files for here-docs — some pipes. Either way tar -c completes and the shell stashes its output before rm runs. Because rm ignores stdin its left hanging for tar -x when rm finishes — and the shell can divest itself of the copy it saved of your file(s). Here-docs can be used like aimed pipes a lot of the time.
How to delete all the files/folders from the folder except few folders?
Now I want to delete all the folders except config and logs (in this case, only src ). my PWD is currently a parent of appliaction/ dir (i.e. I can see application in my PWD ). What command should I use? (I tried with rm -rf with some options but mistakenly deleted other files, so I would like to know the correct answer before trying anything else!)
4 Answers 4
Try find ./application/ -type d -not -name config -not -name logs .
If that returns the proper directories, run
find ./application/ -type d -not -name config -not -name logs -exec rm -R <> \;
The exec rm -R <> \; at the end removes the directory even if it is not empty.
This way is a little more work than some other possible solutions, but when I’m deleting files I like to be able to double check what’s going away forever. The steps below assume you can see «application» in your PWD, as stated in your question.
First create a new text file containing the names of every folder you want to keep (not delete), with one folder per line. Save it as to-keep.txt for example:
Then copy the following into a text editor and save it as rm-exclude.sh so that all three files are in the same directory.
#!/usr/bin/env bash find "./$1" -maxdepth 1 -type d ! -path "./$1" > to-delete.txt dels=`cat to-delete.txt` readarray -t keeps < to-keep.txt for keep in "$"; do dels=`echo "$dels" | grep -v "$keep"` done echo "$dels" > to-delete.txt
Then run it with the following, where PATH is the path to the «application» folder from your PWD. In your example, PATH would simply be application .
Finally, check to-delete.txt to make sure nothing is getting deleted that shouldn’t be, and run:
If you don’t care about checking the contents of the txt file, you can simply copy and paste the above command to the end of rm-exclude.sh so that running the script does everything as long as you have to-keep.txt already filled out. The end result should be that every direct subfolder of application not in to-keep.txt will be deleted, along with their contents.