Delete all files/directories except two specific directories
Solution 1
find
's -prune
comes to mind, but it's a pain to get it to work for specific paths (icecream/cupcake/
) rather than specific directories (cupcake/
).
Personally, I'd just use cpio
and hard-link (to avoid having to copy them) the files in the directories you want to keep to a new tree and then remove the old one:
find test -path 'test/icecream/cupcake/*' -o -path 'test/mtndew/livewire/*' | cpio -padluv test-keep
rm -rf test
That'll also keep your existing directory structure for the directories you intend to keep.
Solution 2
This command will leave only the desired files in their original directories:
find test \( ! -path "test/mtndew/livewire/*" ! -path "test/icecream/cupcake/*" \) -delete
No need for cpio. It works on Ubuntu, Debian 5, and Mac OS X.
On Linux, it will report that it cannot delete non-empty directories, which is exactly the desired result. On Mac OS X, it will quietly do the right thing.
Solution 3
Everything "except" is why we have if-statements; and why os.walk's list of directories is a mutable list.
for path, dirs, files in os.walk( 'root' ):
if 'coke' in dirs:
dirs.remove('coke')
dirs.remove('pepsi')
Solution 4
You could do something based on Python's os.walk function:
import os
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
...just add something to ignore the paths you're interested in.
Solution 5
find /path/to/test/ -depth -mindepth 1 \
! -path "/path/to/test/icecream/cupcake/*" \
! -path "/path/to/test/icecream/cupcake" \
! -path "/path/to/test/icecream" \
! -path "/path/to/test/mtndew/livewire/*" \
! -path "/path/to/test/mtndew/livewire" \
! -path "/path/to/test/mtndew"
-delete -print
It's a bit tedious to write all the paths to preserve but thi is the only way to use find alone.
phuzion
Hi. I enjoy life and computers. I dislike writing biographies about myself. Getting to know me personally is 100 times better than reading a short text blurb about me, so follow me on twitter or something.
Updated on June 19, 2022Comments
-
phuzion almost 2 years
So, there seems to be a few questions asking about removing files/directories matching certain cases, but I'm looking for the exact opposite: Delete EVERYTHING in a folder that DOESN'T match my provided examples.
For example, here is an example directory tree:
. |-- coke | |-- diet | |-- regular | `-- vanilla |-- icecream | |-- chocolate | |-- cookiedough | |-- cupcake | | |-- file1.txt | | |-- file2.txt | | |-- file3.txt | | |-- file4.txt | | `-- file5.txt | `-- vanilla |-- lol.txt |-- mtndew | |-- classic | |-- codered | |-- livewire | | |-- file1.txt | | |-- file2.txt | | |-- file3.txt | | |-- file4.txt | | `-- file5.txt | `-- throwback `-- pepsi |-- blue |-- classic |-- diet `-- throwback
I want to delete everything but the files in test/icecream/cupcake/ and test/mtndew/livewire/. Everything else can go, including the directory structure. So, how can I achieve this? Languages I wouldn't mind this being in: bash or python.
-
phuzion almost 15 yearsTried this, and it says the following: find /home/phuzion/test/ \( -prune 'icecream/cupcake/' \) -delete find: paths must precede expression
-
SourceSeeker almost 15 yearsFrom the man page for find: "Because -delete implies -depth, you cannot usefully use -prune and -delete together."
-
SourceSeeker almost 15 yearsThe correct syntax would be more like "find $directory -path ./pepsi/diet -prune -o -exec some-command '{}' \;" anyway to eliminate that error message.
-
SourceSeeker almost 15 yearsIn your first example, it will rm -r test/icecream which will include cupcake (for example). So, even though you've grep -v the cupcakes, they still get "eaten". The second example has a couple of typos and unbalanced single quotes. There should be a space after sed and the zero should be an ampersand.
-
SourceSeeker almost 15 yearsThis finds test and deletes it, thus deleting the directories that you're trying to save.
-
Patrick Webster almost 15 yearsThis finds test and does NOT delete it, because it is non-empty. Are there any modern flavors of Linux or Unix where this command fails to work?
-
SourceSeeker almost 15 yearsSorry, I made a mistake in setting up the test on my system. Your example works correctly for me.
-
SourceSeeker almost 15 yearsYou still have unbalanced single quotes around the paths. For example, it should be "rm './test/icecream/cupcake/'"
-
kevinmicke over 7 yearsThough it wasn't the original question, some may find this useful: you can preserve the entire directory structure and only delete files not excluded with
test
by adding the-type f
flag before-delete
.