2

I am trying to use the find command to do the following:
Delete a whole folder with files, folders and subfolders except for 2 files, here is an example of what I need:

 test/folder1/file1.txt
 test/folder1/file2.txt
 test/folder1/subfolder1/
 test/folder1/subfolder1/file3.txt
 test/folder1/subfolder1/subfolder2/file4.txt
 test/folder2/file5.txt
 test/folder3/file6.txt

I need to delete everything except for file2.txt and file3.txt

Here is what I already did

 find /test* ! -path '/test/folder1/file2.txt' -a ! -path 'test/folder1/subfolder1/file3.txt'

This will list me all the files except the ones I specified. However if I add -exec rm -rf {} by the end of the command it will delete everything.

I have also tried this other command and didn't work

rm -r  test/folder1/ !(file2.txt|file3.txt)

I don't know much about regular expression so I am trying to make it work by testing commands I found online, however none of them seems to be working.

don_crissti
  • 82,805

2 Answers2

1

Don't call rm -rf. As soon as you run it on a directory, that deletes all the files in the directory and the subdirectories, even the ones you wanted to keep. More generally, don't call rm -rf unless you know why a simple rm won't do. Here, rm -f is warranted if you want to be sure that your script won't ask for confirmation to delete a read-only file, but -r is clearly not warranted.

To just delete the files:

find /test* ! -path '/test/folder1/file2.txt' -a ! -path 'test/folder1/subfolder1/file3.txt' -a -exec rm -f {} +

If you also want to delete the directories that become empty, call rmdir on them. Use -depth so that the directory contents are considered before the directory itself.

find /test* ! -path '/test/folder1/file2.txt' -a ! -path 'test/folder1/subfolder1/file3.txt' -a \( -type d rmdir {} \; -o -exec rm -f {} \; \)

You'll get errors from rmdir running on non-empty directories, they're annoying but harmless.

If your find has -delete and -empty (e.g. GNU find), you don't need to call rm and rmdir.

find /test* ! -path '/test/folder1/file2.txt' -a ! -path 'test/folder1/subfolder1/file3.txt' -a ! -type d ! -empty -delete
0

Look, I also don't know offhand how to do it with find options but you can also use shell scripting in you find:

First delete files:

 find . -type f -exec bash -c \
    ' [[ "{}" == "./test/folder1/file2.txt" || \
         "{}" == "./test/folder1/subfolder1/file3.txt" ]] \
      || rm "{}" ' \;

And then delete all not empty folders:

find .  -type d -exec rmdir {} \; 2>/dev/null