Selective Sub Directory Deleting - linux

So far i have this script.
my folder structure for now is /root/test/
inside test a folder gets created each month named May Jun July based on (date +%B)
i want the script to delete all sub directory's minus the directory that matches this months (date +%B) and keeping its contents.
currently it deletes everything apart from the sub directory matching. May is completely empty. any ideas?
#!/bin/bash
LinkDest=/root/test
m_date=$(date +%B)
find $LinkDest/ -not -name May -xdev -depth -mindepth 1 -exec rm -Rf {} \;

You can use:
find $LinkDest/ -not -path "*$m_date*" -xdev -depth -mindepth 1 -exec rm -Rf '{}' \;

Try running the find without the -exec to see what's going to be removed. The problem is that -name tries to match the whole name, not a part of it. You need -path:
find -not -path "*/$m_date" -not -name $m_date

Related

Delete files in dir but exclude 1 subdir

I have a dir that is full of many htm reports that I keep around for 30 days and delete old ones via a cron, but there is one sub-dir I would like to keep longer. So this is the line I made in the cron, but how do I tell it to leave one sub-dir alone.
5 0 * * * find /var/www -name "*.htm*" -type f -mtime +30 -exec rm -f {} \;
Any help is greatly appreciated!
Use -prune to prevent going into a directory that matches some conditions.
find /var/www -type d -name 'excluded-directory' -prune -o -name "*.htm*" -type f -mtime +30 -exec rm -f {} \;
In addition to suggestion below, suggesting to use full path in cron.
Also to use find option -delete in-place of -exec rm -f {} \;. It is somewhat safer.
-delete
Delete found files and/or directories. Always returns true.
This executes from the current working directory as find recurses
down the tree. It will not attempt to delete a filename with a
"/" character in its pathname relative to "." for security
reasons. Depth-first traversal processing is implied by this
option. The -delete primary will fail to delete a directory if
it is not empty. Following symlinks is incompatible with this
option.
5 0 * * * /usr/bin/find /var/www -type d -name 'excluded-directory' -prune -o -name "*.htm*" -type f -mtime +30 -delete

Remove files in subdirectories older than 1 day with Linux command

I am honestly nowhere near to be a decent bash scripter, but I made a little research and found a command that seems to be useful
find /path/to/files* -mtime +1 -exec rm {} \;
The question is if this line will remove directories? Because I want to only remove files that are images (actually in a *.jpeg format)
No, rm without the -r flag does not remove directories.
It looks like you want to add some more filters:
-type f to match only files
-name '*.jpeg' to match only files ending with .jpeg
Lastly, instead of -exec rm {} \;, you could use the much simpler -delete.
Putting it together, this looks more appropriate for you:
find /path/to/files* -mtime +1 -type f -name '*.jpeg' -delete
Then narrow your search results to *.jpeg files:
find /path/to/files* -mtime +1 -type f -name "*.jpeg" -exec rm {} \;
It's always better to remove the exec parameter to do a dry run before delete:
find /path/to/files* -mtime +1 -type f -name "*.jpeg"
Each line will be passed to rm command, and nothing more.

Shell script to loop and delete

Could someone help me on this.I have below folder structure as shown below .I want to loop through every folder inside the backuptest and delete all the folders except today date folder.i want it run as a cron job
Use find for this:
today="$(date +%Y-%m-%d)"
find /path/to/backuptest/Server* -mindepth 1 -maxdepth 1 -type d -not -name "$today" -exec rm -R {} \;
Edit
To not delete directories other than those containing a date structure, use something like
find /path/to/backuptest/Server* -mindepth 1 -maxdepth 1 -type d -regex ".*2016-[0-1]*[0-9]-[0-3][0-9]$" -not -name "$today"
You can get today's date in whatever format you require via the date command. For example,
TODAY=$(date +%Y-%m-%d)
You can loop over the subfolders you want with a simple wildcard match:
for d in /path/to/backuptest/*/*; do
# ...
done
You can strip the directory portion from a file name with the basename command:
name=$(basename path/to/file)
You can glue that together something like this:
#!/bin/bash
TODAY=$(date +%Y-%m-%d)
for d in /path/to/backuptest/*/*; do
test "$(basename "$d")" = "$TODAY" || rm -rf "$d"
done
Update:
If you don't actually want to purge all subfolders except today's, but rather only those matching some particular name pattern, then one way to accomplish that would be to insert that pattern into the glob in the for command. For example, here
for d in /path/to/backuptest/*/+([0-9])-+([0-9])-+([0-9]); do
test "$(basename "$d")" = "$TODAY" || rm -rf "$d"
done
the only files / directories considered for deletion are those whose names consist of three nonempty, hyphen-separated strings of decimal digits. One could write patterns that more precisely match date string format if one preferred, but it does get messier the more discriminating you want the pattern to be.
You can do it with find:
set date=`date +%Y-%m-%d`
find backuptest -type d -not -name $date -not -name "backuptest" -not -name "Server*" -exec rm -rf {} \;
This:
find backuptest -type d -not -name $date -not -name "backuptest" -not -name "Server*"
will look for directories name different than:
backuptest
Server*
$date -> current date
and remove them with:
rm -rf

How to remove folders with a certain name

In Linux, how do I remove folders with a certain name which are nested deep in a folder hierarchy?
The following paths are under a folder and I would like to remove all folders named a.
1/2/3/a
1/2/3/b
10/20/30/a
10/20/30/b
100/200/300/a
100/200/300/b
What Linux command should I use from the parent folder?
If the target directory is empty, use find, filter with only directories, filter by name, execute rmdir:
find . -type d -name a -exec rmdir {} \;
If you want to recursively delete its contents, replace -exec rmdir {} \; with -delete or -prune -exec rm -rf {} \;. Other answers include details about these versions, credit them too.
Use find for name "a" and execute rm to remove those named according to your wishes, as follows:
find . -name a -exec rm -rf {} \;
Test it first using ls to list:
find . -name a -exec ls {} \;
To ensure this only removes directories and not plain files, use the "-type d" arg (as suggested in the comments):
find . -name a -type d -exec rm -rf {} \;
The "{}" is a substitution for each file "a" found - the exec command is executed against each by substitution.
This also works - it will remove all the folders called "a" and their contents:
rm -rf `find . -type d -name a`
I ended up here looking to delete my node_modules folders before doing a backup of my work in progress using rsync. A key requirements is that the node_modules folder can be nested, so you need the -prune option.
First I ran this to visually verify the folders to be deleted:
find . -type d -name node_modules -prune
Then I ran this to delete them all:
find . -type d -name node_modules -prune -exec rm -rf {} \;
Thanks to pistache
To delete all directories with the name foo, run:
find -type d -name foo -a -prune -exec rm -rf {} \;
The other answers are missing an important thing: the -prune option. Without -prune, GNU find will delete the directory with the matching name and then try to recurse into it to find more directories that match. The -prune option tells it to not recurse into a directory that matched the conditions.
This command works for me. It does its work recursively
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
. - current folder
"node_modules" - folder name
find ./ -name "FOLDERNAME" | xargs rm -Rf
Should do the trick. WARNING, if you accidentally pump a . or / into xargs rm -Rf your entire computer will be deleted without an option to get it back, requiring an OS reinstall.
Combining multiple answers, here's a command that works on both Linux and MacOS
rm -rf $(find . -type d -name __pycache__)
I had more than 100 files like
log-12
log-123
log-34
....
above answers did not work for me
but the following command helped me.
find . -name "log-*" -exec rm -rf {} \;
i gave -type as . so it deletes both files and folders which starts with log-
and rm -rf deletes folders recursively even it has files.
if you want folders alone
find -type d -name "log-*" -exec rm -rf {} \;
files alone
find -type f -name "log-*" -exec rm -rf {} \;
Another one:
"-exec rm -rf {} \;" can be replaced by "-delete"
find -type d -name __pycache__ -delete # GNU find
find . -type d -name __pycache__ -delete # POSIX find (e.g. Mac OS X)
Earlier comments didn't work for me since I was looking for an expression within the folder name in some folder within the structure
The following works for a folder in a structure like:
b/d/ab/cd/file or c/d/e/f/a/f/file
To check before using rm-rf
find . -name *a* -type d -exec realpath {} \;
Removing folders including content recursively
find . -name *a* -type d -exec rm -rf {} \;
find path/to/the/folders -maxdepth 1 -name "my_*" -type d -delete

nonzero return code although find -exec rm works

I'm on a linux system I wonder what is wrong with the following execution of find:
mkdir a && touch a/b
find . -name a -type d -exec echo '{}' \;
./a
find . -name a -type d -exec rm -r '{}' \;
find: `./a': No such file or directory
The invocation of echo is just for testing purposes. I would expect the last command to remove the directory './a' entirely and return 0. Instead it removes the directory and generates the error message. To repeat, it does remove the directory! What is going on?
rm executes without a problem. The issue is that find is confused, since it knew the directory ./a was there, it tries to visit that directory to look for directories named a. However, find cannot enter the directory, since it was already removed.
One way to avoid this is to do
find -name a -type d | xargs rm -r
This will let the find move along before the rm command is executed. Or, you can simply ignore the error in your original command.
Based on epsalon's comment the solution is to use the -depth option which causes the deeper files to be visited first.
find . -depth -name a -type d -exec rm -r '{}' \;
does the trick. Thanks a bunch!
If performance is an issue, use -prune in order to prevent find from descending into directories named "a":
find . -name a -type d -prune -exec rm -r '{}' \;

Resources