-2

I'm trying to use the find command, but still can't figure out how to pipe the find ... to rm -rf

Here is the directory tree for testing:

/path/to/directory
/path/to/directory/file1_or_dir1_to_exclude
/path/to/directory/file2_or_dir2_to_exclude
/path/to/directory/.hidden_file1_or_dir1_to_exclude
/path/to/directory/.hidden_file2_or_dir2_to_exclude

/path/to/directory/many_other_files
/path/to/directory/many_other_directories

Here is the command for removing the whole directory:

rm -rf /path/to/directory

But how to rm -rf while excluding files and folders?

Here is the man help for reference:

man find

-prune True;  if  the  file is a directory, do not descend into it.  If
      -depth is given, then -prune has no effect.  Because -delete im‐
      plies  -depth,  you  cannot  usefully use -prune and -delete to‐
      gether.
        For example, to skip the directory `src/emacs' and  all  files
      and directories under it, and print the names of the other files
      found, do something like this:
                find . -path ./src/emacs -prune -o -print

What's the -o in this find command? Does it mean "or"? I can't find the meaning of -o in the man page.

mkdir -p /path/to/directory

mkdir -p /path/to/directory/file1_or_dir1_to_exclude
mkdir -p /path/to/directory/file2_or_dir2_to_exclude

mkdir -p /path/to/directory/.hidden_file1_or_dir1_to_exclude
mkdir -p /path/to/directory/.hidden_file2_or_dir2_to_exclude

mkdir -p /path/to/directory/many_other_files
mkdir -p /path/to/directory/many_other_directories

I have tried to use this find command to exclude the .hidden_file1_or_dir1_to_exclude and then pipe it to rm, but this command does not work as expected.

cd /path/to/directory
find . -path ./.hidden_file1_or_dir1_to_exclude -prune -o -print | xargs -0 -I {} rm -rf {}
tripleee
  • 175,061
  • 34
  • 275
  • 318
stackbiz
  • 1,136
  • 1
  • 5
  • 22
  • It means "or". Recall that expression stops evaluating when or is true so the rest is not done. Debug the expression you want with print, then change to rm. – stark Aug 28 '21 at 11:36
  • Hi stack, thanks for your help. Now I have understand the meaning of "-o" in the find comand, but still don't know how to pipe it to the "rm -rf". I have updated the question to include the testing script, can you help to check it again? Thanks. – stackbiz Aug 28 '21 at 12:26

2 Answers2

1

The meaning of rm -rf is to recursively remove everything in a directory tree.

The way to avoid recursively removing everything inside a directory is to get find to enumerate exactly the files you want to remove, and nothing else (and then of course you don't need rm at all; find knows how to remove files, too).

find . -depth -path './.hidden_file1_or_dir1_to_exclude/*' -o -delete

Using -delete turns on the -depth option, which disables the availability of -prune; but just say "delete if not in this tree" instead. And indeed, as you seem to have discovered already, -o stands for "or".

The reason -delete enables -depth should be obvious; you can't traverse the files inside a directory after you have deleted it.

As an aside, you need to use -print0 if you use xargs -0. (This facility is a GNU extension, and generally not available on POSIX.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • This command does not work, it says: find: The -delete action automatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option. – stackbiz Aug 28 '21 at 12:55
  • Thanks for the feedback - updated now, but probably try it with `-print` instead of `-delete` first! – tripleee Aug 28 '21 at 13:00
  • I have tried the latest command but it does not exclude the folder: find . -depth -path './.hidden_file1_or_dir1_to_exclude/*' -o -delete – stackbiz Aug 28 '21 at 13:05
  • Thanks tripleee! Thanks for your help, the "-print0" works in this command: find . -path ./.hidden_file1_or_dir1_to_exclude -prune -o -print0 | xargs -0 -I {} rm -rf {} – stackbiz Aug 28 '21 at 13:11
0

You need to separate files from directories to exclude:

find . -mindepth 1\
       \( -path ./dir_to_exclude -o\
          -path ./.hidden_dir_to_exclude \) -type d -prune\
       -o\
     ! \( -path ./file_to_exclude -o\
          -path ./.hidden_file_to_exclude \)\
        -exec echo rm -rf {} \;

You can remove the echo once tested.

tripleee
  • 175,061
  • 34
  • 275
  • 318
Philippe
  • 20,025
  • 2
  • 23
  • 32