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
  • 79,330
  • 30
  • 216
  • 245
  • I'd suggest two passes - a 'find -type f' that calls a simple "-delete" on the files that you want to remove. Then run a 'find -type d' with an 'exec rmdir' (keeping your exclusions intact for both runs). – Jeff Schaller Apr 14 '16 at 18:08
  • [`{ rm -rf test/*; tar -x; } <<< $(tar -c test/**/file1 test/**/file2.txt)`](http://unix.stackexchange.com/a/153869) with `zsh` or `bash` + `shopt -s globstar` – don_crissti Apr 15 '16 at 09:51

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
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
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