Delete nested subdirectories by name on Mac? - macos

How can I delete all subdirectories of a certain name via the command line on mac?
Eg if I have
/parent/foo
/parent/child/foo
/parent/child/child2/foo
How can I run a command from /parent that will delete any folder called foo and all of it's contense?
Ive tried this command but no luck:
find . -type d -name foo -delete

Using find you can do:
find . -d -type d -name a -exec rm -r {} \;
As you have discovered -delete does not appear to delete non-empty directories (so its equivalent to rmdir not rm -r), though this may not be documented.
The -exec executes a command, {} is replaced by the matching pathname, and \; marks the end of the command. So this does a recursive removal of every matching path.
The -d sets depth first traversal which means directories are processed after their contents. If you omit this find will first remove the directory and then try to recurse into it – this results in error messages but still works.
There is a shorter way using zsh:
rm -r **/a
The pattern ** does a search an matches a at any depth.
If zsh is not your default shell you can use its -c argument to run a command from another shell:
zsh -c 'rm -r **/a'
HTH

The name of the directory has to be in quotes.
Do the following:
find . -type d -name "foo" -delete

Related

How to concatenate string to -print in unix find command?

I have this command to run in Unix machine where I'm deleting all directories from specific folder if they are older then 1 day:
find /path_with_dirs_to_delete/* -type d -mtime +1 -prune -exec rm -rf {} + -print
It's currently printing out the folder names and i want to concatenate to the printing output the text " was deleted successfully".
How can I do that?
If using GNU tools, a superior solution is to add the -v (verbose) flag to rm.
For a POSIX solution you could do this:
find /path/* -type d -mtime +1 -prune -exec rm -rf {} \; -exec echo {} was deleted successfully \;
You were running a single rm to remove multiple directories. But if you want to test rm's success for each directory, it has to run once per directory (note ; instead of +). Note that this a bit less efficient.
-a ("and") is implied between find actions, meaning the second -exec action (echo) only runs if the previous one (rm) succeds. So this can be used to log a successful removal.
You will receive an error message from rm if a removal fails (eg. permission denied).
rm -f suppresses "does not exist" errors, and you wouldn't get a success message either, however find won't pass a non-existent directory.

How to delete all files or Sub-folders (both) in a folder except 2 folders with shell script

I would like to know how to deleted all the contents of a folder (it contains other folders and some files) except for 2 folders and its contents
The below command keeps the folder conf and removes all the other folders
find . ! -name 'conf' -type d -exec rm -rf {} +
I have tried to pipe it like below
find . -maxdepth 1 -type d ! -name 'conf' |find . -maxdepth 1 -type d ! -name 'foldername2'
but didnt work.
is it possible to do with a single command
You haven't specified which shell you're using, but if you're using bash then extended globs can help:
printf '%s\n' !(#(conf|foldername2)/)
If you're happy with the list of files and directories produced by that, then pass the same glob to rm -rf:
rm -rf !(#(conf|foldername2)/)
Inside a script, you may need to enable extglob using shopt -s extglob. Later, you can change -s to -u to unset the option.
If you're using a different shell, then you can add some more options to your find command:
find -maxdepth 1 ! -name 'conf' -a ! -name 'foldername2' -exec rm -rf {} +
Try it without the -exec part first to print the matches rather than deleting everything.
It may my little program utility can help you. I hope so.
First of all you should find the path of your files .sh
then you should find the main folder that contains those files .sh
then remove anything except those folders
I wrote drr for such a purpose that it can do such a task so easy
drr, stands for: remove or rename files based on regular expression in D language. So you must compile it before using.
See the screenshot:
Please be careful since this is not an appropriate tool for beginner.

How to move files en-masse while skipping a few files and directories

I'm trying to write a shell script that moves all files except for the ones that end with .sh and .py. I also don't want to move directories.
This is what I've got so far:
cd FILES/user/folder
shopt -s extglob
mv !(*.sh|*.py) MoveFolder/ 2>/dev/null
shopt -u extglob
This moves all files except the ones that contain .sh or .py, but all directories are moved into MoveFolder as well.
I guess I could rename the folders, but other scripts already have those folders assigned for their work, so renaming might give me more trouble. I also could add the folder names but whenever someone else creates a folder, I would have to add its name to the script or it will be moved as well.
How can I improve this script to skip all folders?
Use find for this:
find -maxdepth 1 \! -type d \! -name "*.py" \! -name "*.sh" -exec mv -t MoveFolder {} +
What it does:
find: find things...
-maxdepth 1: that are in the current directory...
\! -type d: and that are not a directory...
\! -name "*.py: and whose name does not end with .py...
\! -name "*.sh: and whose name does not end with .sh...
-exec mv -t MoveFolder {} +: and move them to directory MoveFolder
The -exec flag is special: contrary to the the prior flags which were conditions, this one is an action. For each match, the + that ends the following command directs find to aggregate the file name at the end of the command, at the place marked with {}. When all the files are found, find executes the resulting command (i.e. mv -t MoveFolder file1 file2 ... fileN).
You'll have to check every element to see if it is a directory or not, as well as its extension:
for f in FILES/user/folder/*
do
extension="${f##*.}"
if [ ! -d "$f" ] && [[ ! "$extension" =~ ^(sh|py)$ ]]; then
mv "$f" MoveFolder
fi
done
Otherwise, you can also use find -type f and do some stuff with maxdepth and a regexp.
Regexp for the file name based on Check if a string matches a regex in Bash script, extension extracted through the solution to Extract filename and extension in Bash.

How to delete a file in any of the directories or subdirectories except one subdirectory

I want to delete a file from a directory which contains many subdirectories but the deletion should not happen in one subdiretory(searc) whose name is already predefined but path varies as shown below.So now how to delete a file i am using the below command
find . -type f -name "*.txt" -exec rm -f {} \;
this command deletes all the files in the directory.So How can we delete the file without serching that subdirectory.
The subdirectory file name will be same but the path will different
for eg
Main
|
a--> searc
|
b-->x--->searc
|
c-->y-->x-->searc
now the
the subdirectory not to be searched can be present any where as shown above
I think you want the -prune option. In combination with a successful name match, this prevents descent into the named directories. Example:
% mkdir -p test/{a,b,c}
% touch test/{a,b,c}/foo.txt
% find test -name b -prune -o -name '*.txt' -print
test/a/foo.txt
test/c/foo.txt
I am not completely sure what you're asking, so I can give only somewhat generic advice.
You already know the -name option. This refers to the filename only. You can, however, also use -wholename (a.k.a. -path), which refers to the full path (beginning with the one given as first option to find).
So if you want to delete all *.txt files except in the foo/bar subdirectory, you can do this:
find . -type f -name "*.txt" ! -wholename "./foo/bar/*" -delete
Note the -delete option; it doesn't require a subshell, and is easier to type.
If you would like to exclude a certain directory name regardless of where in the tree it might be, just don't "root" it. In the above example, foo/bar was "rooted" to ./, so only a top-level foo/bar would match. If you write ! -wholename "*/foo/bar/*" instead (allowing anything before or after via the *), you would exclude any files below any directory foo/bar from the operation.
You can use xargs instead of the exec
find .... <without the --exec stuff> | grep -v 'your search' | xargs echo rm -f
Try this first. If it is satisfactory, you can remove the echo.

What does the -exec option to 'find' do?

I am new to Makefile. I was going through an existing makefile and couldn't understand what it does. The line is as below.
find $(RELEASE_DIR) -depth -name "*CVS" -exec rm -rf {} \;
find command is used to find the strings. But I could not understand what this line exactly do. Please help to understand.
The find command is there to search for files in a given directory.
find <directory> -option1 -option2
The option -name "*CVS" says that the command will search for files with CVS in the end of their name.
-depth means that the directories are traversed with the http://en.wikipedia.org/wiki/Depth-first_search method.
-exec rm -rf {} \; tells find to execute the command rm -rf for every file that was found. {} is a placeholder for the currently found file and \; marks the end of the rm command.
This mean that it will scan the $(RELEASE_DIR) and for each file that have a name like *CVS we execute rm -rf, this mean delete it.
=> This command delete all files that contain CVS in the end of their name.

Resources