How to purge old directories programmatically in unix/shell? - unix

Does anyone have a good shell line for this?
I want to check the age on a directory. If I created multiple directories on a weekly basis and I want to purge them/delete them based on 7 days later for example.
How would I do that?

This will let you do a dry run, remove the echo if you like the output
find /path/to/toplevel -type d -mtime +7 -exec echo rm -rf {} +
Update
If you have an older version of find that doesn't comply with POSIX 2004 then use this instead:
find /path/to/toplevel -type d -mtime +7 -exec echo rm -rf {} \;
or
find /path/to/toplevel -type d -mtime +7 -print0 | xargs -0 echo rm -rf {}
The former terminated by \; will call rm for each directory it finds, the latter with xargs will attempt to call rm as few times as possible by passing multiple directories to a single call to rm and thus be much faster. The latter also has identical behavior to the first one terminated with a +

Related

alternatives to long-running `find` command in unix

I want to delete files that are older than 7 days, and I'm using this command to do so:
find /directory -mtime +7 -exec rm -f {} \;
It is working fine except it takes too long. Is there any other way to delete files older than 7 days, e.g. without using find?
Using "-exec rm" is known to slow things down. If your find has the -delete option, then try using it instead, like so:
find /directory -type f -mtime +7 -delete
If your find does not have the -delete option, then consider using GNU find (which might already be available on your system as gfind).
There are other possibilities, e.g. using xargs. For further discussion and some other options, see Deleting-Files.
Change the final ; for a plus sign +
$ find /directory -type f -mtime +7 -exec rm -f {} \+
or use xargs command:
$ find /directory -type f -mtime +7 | xargs rm
Both will be at least 3 times faster

Delete directory based on date

I am writing zsh script in which I have to get the date of 90th previous day from current date i.e I have to subtract 90 days from current date. Then I have to check the folders which have different dates as their names. I have to compare the directory date with the subtracted date and if the result is greater than the subtracted date, I have to delete the directory.
For example:
Let us say the current_date = 20131130 (yyyymmdd)
subtracted_date=current_date - 90 days
lets say there is a folder 20130621
Now this folder name should be compare with the subtracted date. If greater than subtracted_date then i have to delete the directory.
find path -type d -ctime +90 -exec rm -rf {} \;
should find all directories older than 90 days and use rm -rf on them
Be careful with that command though you will probably want to test it first with this
find path -type d -ctime +90 -exec echo {} \;
in order to keep certain folders consider -mtime instead of -ctime and touch the folder every so often
replace path above with the actual path you want to scan and delete
explanation
find is the command
path is the root directory you want to scan
-type d means look for directories only
-ctime +90 means created time older than 90 days
-exec rm -rf {} \; means remove recursively and force delete of the items which were found
-mtime is modified time
The second command will list out all folder which will be deleted so is much safer to run while you are testing
List directories before delete
find . -type d -ctime +60 -ls
List files before delete
find . -type f -ctime +60 -ls
Delete directories in current directory
find . -type d -ctime +60 -exec rm -rf {} \;
Delete files in current directory
find . -type f -ctime +60 -exec rm -rf {} \;
You can use the date command to find the date 90 days earlier to the current one. The following script should give you a list of directories that need to be deleted:
del=$(date --date="90 days ago" +%Y%m%d)
for i in `find . -type d -name "2*"`; do
(($del > $(basename $i))) && echo "delete $i" || echo "dont delete $i"
done
To perform the actual deletion of directories, you can replace the third line with the following:
(($del > $(basename $i))) && rm -rf $i
For example, if your current directory contains the following folders:
$ ls -1F
20120102/
20130104/
20130302/
20130402/
20130502/
20130602/
20130702/
Executing the above script would tell:
$ bash cleanup
delete ./20130302
delete ./20130104
delete ./20120102
delete ./20130402
dont delete ./20130702
dont delete ./20130502
dont delete ./20130602
You can also use the following command to delete all files in the current directory by date .
[jamshi#cpanel ~]$ rm -rf ls -l | grep 'Jul 19 15:32' | tr -s ' ' | cut -d ' ' -f9

How to move or copy files listed by 'find' command in unix?

I have a list of certain files that I see using the command below, but how can I copy those files listed into another folder, say ~/test?
find . -mtime 1 -exec du -hc {} +
Adding to Eric Jablow's answer, here is a possible solution (it worked for me - linux mint 14 /nadia)
find /path/to/search/ -type f -name "glob-to-find-files" | xargs cp -t /target/path/
You can refer to "How can I use xargs to copy files that have spaces and quotes in their names?" as well.
Actually, you can process the find command output in a copy command in two ways:
If the find command's output doesn't contain any space, i.e if the filename doesn't contain a space in it, then you can use:
Syntax:
find <Path> <Conditions> | xargs cp -t <copy file path>
Example:
find -mtime -1 -type f | xargs cp -t inner/
But our production data files might contain spaces, so most of time this command is effective:
Syntax:
find <path> <condition> -exec cp '{}' <copy path> \;
Example
find -mtime -1 -type f -exec cp '{}' inner/ \;
In the second example, the last part, the semi-colon is also considered as part of the find command, and should be escaped before pressing Enter. Otherwise you will get an error something like:
find: missing argument to `-exec'
find /PATH/TO/YOUR/FILES -name NAME.EXT -exec cp -rfp {} /DST_DIR \;
If you're using GNU find,
find . -mtime 1 -exec cp -t ~/test/ {} +
This works as well as piping the output into xargs while avoiding the pitfalls of doing so (it handles embedded spaces and newlines without having to use find ... -print0 | xargs -0 ...).
This is the best way for me:
cat filename.tsv |
while read FILENAME
do
sudo find /PATH_FROM/ -name "$FILENAME" -maxdepth 4 -exec cp '{}' /PATH_TO/ \; ;
done

Cron Job - Delete old files, but keep files from the first of the month

I'm currently running successful mysql backups, and, on some sites, I'm deleting files older that 7 days using this command
find /path/to/file -mtime +7 -exec rm -f {} \;
What I'd like to do, because I'm paranoid and would still like some archived information, is delete files older than 31 days, but maintain at least one file from each previous month, perhaps spare any file that was created on the 1st of the month.
Any ideas?
You can also write a script to contain something like this using xargs:
find /path/to/files -mtime +7| xargs -i rm {};
then add the script to your cron job
The grep is almost right, it only has one space too many. This works (at least for me, I use Debian):
rm `find /path/to/file -type f -mtime +7 -exec ls -l {} + | grep -v ' [A-S][a-z][a-z] 1 ' | sed -e 's:.* /path/to/file:/path/to/file:g'`
You can create a file with these commands:
SRC_DIR=/home/USB-Drive
DATE=$(/bin/date "+%4Y%2m%2d%2H%2M")
TIME_STAMP=$(/bin/date --date 'now' +%s)
TIME_CAL=$[$TIME_STAMP-2592000+25200] #last day, 25200 is my GMT+7hour
TIME_LAST=$(/bin/date --date "1970-01-01 $TIME_CAL sec" "+%4Y%2m%2d%2H%2M")
/bin/touch -t ${TIME_LAST} /tmp/lastmonth
/usr/bin/find -P -H ${SRC_DIR} ! -newer /tmp/lastmonth -type d -exec rm -r {} \;
You can modified last command based on what you want to delete, in this case I want to delete sub-folders in SRC_DIR. With the 'time attribute' more than 1 month ago.
Kind of ugly, but you can try parsing the output of ls -l
rm `find /path/to/file -type f -mtime +7 -exec ls -l {} + | grep -v ' [A-S][a-z][a-z] 1 ' | sed -e 's:.* /path/to/file:/path/to/file:g'`
Or write a script to get the list then run rm on them one at a time.

Why doesn't my 'find' work like I expect using -exec?

I'm trying to remove all the .svn directories from a working directory.
I thought I would just use find and rm like this:
find . -iname .svn -exec 'rm -rf {}' \;
But the result is:
find: rm -rf ./src/.svn: No such file or directory
Obviously the file exists, or find wouldn't find it... What am I missing?
You shouldn't put the rm -rf {} in single quotes.
As you've quoted it the shell is treating all of the arguments to -exec it as a command rather than a command plus arguments, so it's looking for a file called "rm -rf ./src/.svn" and not finding it.
Try:
find . -iname .svn -exec rm -rf {} \;
Just by-the-bye, you should probably get out of the habit of using -exec for things that can be done to multiple files at once. For instance, I would write that out of habit as
find . -iname .svn -print | xargs rm -rf
or, since I'm now using a Macintosh and more likely to encounter file or directory names with spaces in them
find . -iname .svn -print0 | xargs -0 rm -rf
"xargs" makes sure that "rm" is invoked only once every "N" files, where "N" is usually 20. That's not a huge win in this case, because rm is small, but if the program you wanted to execute on every file was large or did a lot of processing on start up, it could make things a lot faster.
maybe its just me, but the old find & rm script does not work on my current config, a la:
find /data/bin/test -type d -mtime +10 -name "[0-9]*" -exec rm -rf {} \;
whereas the xargs solution does, a la:
find /data/bin/test -type d -mtime +10 -name '[0-9]*' -print | xargs rm -rf ;
no idea why, but i've updated my scriptLib so i dont spend another couple hours beating
my head on something so simple....
(running RHEL under kernel-2.6.18-194.11.3.el5)
EDIT: found out why - my RHEL distro defaults vi to insert the dreaded cr into line breaks (whch breaks the command) - following suggestions from nx5000 & jliagre at linuxquestions.org, added the following to ~/.vimrc:
:set fileformat=unix
map <F4> :set fileformat=unix<CR>
map <F5> :set fileformat=dos<CR>
which allows the behavior to pivot on the F4/F5.
to check whether CR's are embedded in your file:
head -1 scriptFile.sh | od -c | head -1
http://www.linuxquestions.org/questions/linux-general-1/bad-interpreter-no-such-file-or-directory-213617/
You can also use the svn command as follows:
svn export <url-to-repo> <dest-path>
Look here for more info.
Try
find . -iname .svn -exec rm -rf {} \;
and that probably ought to work IIRC.
You can pass anything you want in quotes, with the following trick.
find . -iname .svn -exec bash -c 'rm -rf {}' \;
The exec option will be happy to see that you're simply calling an executable with an argument, but your argument will be able to contain a script of basically any size and shape.
find . -iname .svn -exec bash -c '
ls -l "{}" | wc -l
' \;

Resources