Find and delete multiple argument directories - bash

Say I have 3 directories .git, .hg and .svn somewhere in the folder called lol.
How can I find and remove all of these?
The following does so only for the last one (.svn):
$ find lol -type d -name .git -o -name .hg -o -name .svn -delete
E: This could be done with ls too but not without shopt -s globstar (since I'm not doing it with zsh):
$ shopt -s globstar
$ rm -r $(ls -d ceaw/**/.{git,hg,svn})
E2: Another solution woulda been:
$ find lol -type d -name .git -o -name .hg -o -name .svn | xargs rm -rf

Try using the -exec option instead.
find lol -depth -type d \( -name .git -o -name .hg -o -name .svn \) -exec rm -r '{}' \;

Related

GNU find following symbolic links and name pattern fails to execute remove (rm)

I tried to remove files which might be located in symlinked directories. I recognized for certain basenames, that find fails with the error No such file or directory.
Here is what I tried. Am I doing something wrong? Thanks!
touch a_b.c.d
touch a_b.d
find -L . -type f -name '*.c.d' -exec bash -c 'rm $(basename {} .c.d).d' \;
This fails, too
touch a_b.c.d
touch a_b.d
find -L . -type f -name '*.c.d' -exec rm a_b.d \;
But this works
touch a_x_b.c.d
touch a_x_b.d
find -L . -type f -name '*.c.d' -exec bash -c 'rm $(basename {} .c.d).d' \;
or this, respectively
touch a_x_b.c.d
touch a_x_b.d
find -L . -type f -name '*.c.d' -exec rm a_x_b.d \;

Delete directories with specific files in Bash Script

I would like to delete specific files if existed but also the directories that contain these files. I do know the files I would like to wipe but not the directories. So far, as I'm new in bash scripting, I think of this :
find ./ -type f -name '*.r*' -print0 | xargs -0 rm -rf &> log_del.txt
find ./ -type f -name '*.c*' -print0 | xargs -0 rm -rf &>> log_del.txt
At the moment, all files named with the specific extensions *.r* and *.c* are deleted.
But the directories are still remaining and also the subdirectories in it, if existed.
I also thought of the option -o in find to delete in one line :
find ./ -type f \( -name '*.r*' -o -name '*.c*' \) -print0 | xargs -0 rm -rf &> log_del.txt
How can I do this?
And I also see that my log_del.txt file is empty... :-(
It looks like what you really want is to remove all empty directories, recursively.
find . -type d -delete
-delete processes the directories in child-first order, so that a/b is deleted before a. If a given directory is not empty, find will just display an error and continue.
If the directories remain empty, let rmdir try to remove all of them. It will fail on any directories which have still files.
find ./ -type d -exec rmdir --ignore-fail-on-non-empty {} 2>/dev/null \;
See if this serves your requirement:
find ./ -type f -name '*.r*' -delete -printf "%h\0" | xargs -0 rmdir
If the directory contained any other files, rmdir will fail.
So consider below sample file structure:
$ find a
a/
a/a/
a/a/4
a/b/
a/b/5
a/b/4
a/b/3
a/b/2
a/b/1
$ find a -type f -name '4' -delete -printf "%h\0" | xargs -0 -r rmdir
rmdir: failed to remove ‘a/b’: Directory not empty
$ find a
a
a/b
a/b/5
a/b/3
a/b/2
a/b/1
If in above example, you want to delete directory b also, you can simply use:
$ find ./ -type f -name '*.r*' -printf "%h\0" | xargs -0 rm -rf
EDIT: As per the comment, you (OP) wanted that the empty directory tree should also be deleted. These 2 commands should help you then:
$ find ./ -type f -name '*.r*' -delete # Delete matching files
$ find ./ -empty -type d -delete # Delete tree of empty directories

Delete a list of file/directory names

I have a list of file and directory names:
foo.js FOOBAR bar.json fubar/ .foo/ .baz
Is there a way to pass them to find, grep or something and delete all with one command?
Why not just use rm?
rm -fr -- foo.js FOOBAR bar.json fubar/ .foo/ .baz
-- is optional if one of your file arguments starts with -.
If you want to recursively delete files with those filenames recursively, you can do this:
find path \( -name foo.js -o -name FOOBAR -o -name bar.json -o -name fubar -o -name .foo -o -name .baz \) -exec rm -fr -- '{}' \;
Similarly with xargs:
find path \( -name foo.js -o -name FOOBAR -o -name bar.json -o -name fubar -o -name .foo -o -name .baz \) -print0 | xargs -0 rm -fr --
You can simply use:
rm -rf foo.js FOOBAR bar.json fubar/ .foo/ .baz.
-r option will remove those files recursively and -f option will remove those files forcefully.
If all the files are in same folder then rm -rf * will do the job!

Why is this command exploding

So I got this as an answer to a previous question as an answer for looking recursively through files in a directory and deleting the files and directories if found:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -exec rm -rf "{}" \;
There are two problems with this:
One:
find: `./adam.balan/AisisAjax/.git': No such file or directory
because of this error the rest of the script doesn't execute. Now I don't want to have to check for any of the files or folders. I don't care if they exist or not, I want to suppress the error on this.
The second is that I am also getting the error on a directory that needs to be excluded from this search: vendor/
find: `./vendor/adam.balan/AisisAjax/.git': No such file or directory
I do not want it searching vendor. I want it to leave vendor alone.
How do I solve these two problems? Suppression and ignoring.
The problem is that you're deleting a directory that find then tries to descend into. You can use -prune to prevent that:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \;
To ignore all errors, you can use 2> /dev/null to squash the error messages, and || true to avoid set -e making your script exit:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true
Finally, to avoid descending any directory named 'vendor', you can use -prune again:
find -name vendor -prune -o \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true

Find and delete old files excluding some subdirectories

I have been searching for a while, but can't seem to get a succinct solution. I am trying to delete old files but excluding some subdirectories (passed via parm) and their child subdirecories.
The issue that I am having is that when the subdirectory_name is itself older than the informed duration (also passed via parm) the find command is including the subdirectory_name on the list of the find. In reality the remove won't be able to delete these subdirectories because the rm command default option is f.
Here is the find commmand generated by the script:
find /directory/ \( -type f -name '*' -o -type d \
-name subdirectory1 -prune -o -type d -name directory3 \
-prune -o -type d -name subdirectory2 -prune -o \
-type d -name subdirectory3 -prune \) -mtime +60 \
-exec rm {} \; -print
Here is the list of files (and subdirectories brought by the find command)
/directory/subdirectory1 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory2 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory3 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory51/file51
/directory/file1 with spaces
Besides this -- the script works fine not bringing (excluding) the files under these 3 subdirectories:
subdirectory1, subdirectory2 and subdirectory3.
Thank you.
Following command will delete only files older than 1 day.
You can exclude the directories as shown in the example below, directories test1 & test2 will be excluded.
find /path/ -mtime +60 -type d \( -path ./test1 -o -path ./test2 \) -prune -o -type f -print0 | xargs -0 rm -f
Though it would be advisable to see what's going to be deleted using -print
find /path/ -mtime +60 -type d \( -path ./test1 -o -path ./test2 \) -prune -o -type f -print
find /directory/ -type d \(
-name subdirectory1 -o \
-name subdirectory2 -o \
-name subdirectory3 \) -prune -o \
-type f -mtime +60 -print -exec rm -f {} +
Note that the AND operator (-a, implicit between two predicates if not specified) has precedence over the OR one (-o). So the above is like:
find /directory/ \( -type d -a \(
-name subdirectory1 -o \
-name subdirectory2 -o \
-name subdirectory3 \) -a -prune \) -o \
\( -type f -a -mtime +60 -a -print -a -exec rm -f {} + \)
Note that every file name matches the * pattern, so -name '*' is like -true and is of no use.
Using + instead of ; runs fewer rm commands (as few as possible, and each is passed several files to remove).
Do not use that code above on directories writeable by others as it's vulnerable to attacks whereby the attacker can change a directory to a symlink to another one in between the time find traverses the directory and calls rm to have you delete any file on the filesystem. Can be alleviated by changing the -exec part with -delete or -execdir rm -f {} \; if your find supports them.
See also the -path predicate if you want to exclude a specific subdirectory1 instead of any directory whose name is subdirectory1.

Resources