linux script that will delete files from previous month - linux

I am new in linux scripting and I have never created .sh file before.
I need to create a script that will delete all the files which are from previous month.
I have gone through the
find /path/to/files* -mtime +5 -exec rm {} \;
but find useless as days in a month can vary from 30 -31 days.
Please help me on this problem. thanks

Run below commands to delete last month file in working Directory.
1st you can see last moth files in working directory run
sudo find . -mtime +30
Numeric arguments can be specified as
+n for greater than n,
-n for less than n,
n for exactly n.
sudo find . -mtime +30 -delete
to delete all files in the systems you can run as below
sudo find / -mtime +30 -delete

Well, first off - how important is it your purge last month? I mean - if you run your script on May 1st, are you really expecting to delete the files from last night?
For most purposes - find -mtime +30 is sufficient, as it's a rolling 30d window.
However, if you really want to 'last month and older' then you have to get a bit more creative, because Unix works on time stamps - in seconds. 30d in seconds is a fixed window, but as you note - 1 calendar month is not.
It gets worse yet if you bear in mind that 'last month' may well also be 'last year' as well.
So to get exactly one month ago:
perl -MTime::Piece -e 'print localtime -> add_months(-1);'
To turn that into a Unix timestamp:
perl -MTime::Piece -e 'print localtime -> add_months(-1) -> epoch;'
To actually figure out the time stamp of the start of the last month is slightly more complicated though - the easiest way is probably to do the above, and then 'figure out' the time stamp of the first day.
E.g.
perl -MTime::Piece -e 'print localtime->strptime(localtime->add_months(-1)->strftime("%Y%m"),"%Y%m);'
We subtract 1 month from today, reformat it as 'year/month' and then re-parse 'year/month' with no day to get the first day of the month.

Obligatory bash solution. From the working directory containing the files to remove, you could run this
for i in $(ls -al | awk '/May/{print $NF}'); do rm -rf $i; done
It will explicitly match all files create in May and then remove them.
The ls -al command lists out the files with their dates and then the awk command matches the files with a date of May and then prints out only the file name. You can test it out before pulling the trigger by running this
ls -al | awk '/May/{print $NF}'
Once you are certain that the files being found are the ones you want to remove, you can run the for loop to remove them.

Related

Issue with Linux find command

I have written a script to create an array of files that are modified more than 1 day back, iterate through the array and delete them interactively. Somehow the script is not working.
Below is the code:
#!/bin/bash
#take input from user for directory
read -p "Please enter the directory path from which you want to remove unused files" path
#create an array of files modified 2 days back
readarray -t files < <(find "$path" -maxdepth 0 -type f -mtime +1)
#remove the files iteratively and interactively
for file in "${files[#]}"; do
rm -i "$file"
done
This script isn't deleting anything. I have some files created on 12th Jan and untouched after that, but they're still there.
Can you please mention if something is missing here?
-mtime only considers full days, meaning +1 means "at least 2 days ago". From man find:
-atime n
File was last accessed less than, more than or exactly n*24 hours
ago. When find figures out how many 24-hour periods ago the file was
last accessed, any fractional part is ignored, so to match -atime +1,
a file has to have been accessed at least two days ago.
-mtime n
File's data was last modified less than, more than or exactly n*24
hours ago. See the comments for -atime to understand how rounding
affects the interpretation of file modification times.
You might also want to consider -exec of find instead of storing in an array. This will avoid all sorts of problems when your file names contain special characters, such as blanks, newlines, or globbing wildcards:
find "$path" -maxdepth 0 -type f -mtime +1440 -exec rm {} +
(a day has 1440 minutes (=60*24))

Find files in created between a date range

I use AIX via telnet here at work, and I'd like to know how to find files in a specific folder between a date range. For example: I want to find all files in folder X that were created between 01-Aug-13 and 31-Aug-13.
Observations:
The touch trick (where you create two empty files to use the -newer option) does not work for me, once the user roles that I have on the server does not allow me to create files.
I need to find between specific dates, not days (like: files that were created more than 30 days ago, etc...)
If you use GNU find, since version 4.3.3 you can do:
find -newerct "1 Aug 2013" ! -newerct "1 Sep 2013" -ls
It will accept any date string accepted by GNU date -d.
You can change the c in -newerct to any of a, B, c, or m for looking at atime/birth/ctime/mtime.
Another example - list files modified between 17:30 and 22:00 on Nov 6 2017:
find -newermt "2017-11-06 17:30:00" ! -newermt "2017-11-06 22:00:00" -ls
Full details from man find:
-newerXY reference
Compares the timestamp of the current file with reference. The reference argument is normally the name of a file (and one of its timestamps is used
for the comparison) but it may also be a string describing an absolute time. X and Y are placeholders for other letters, and these letters select
which time belonging to how reference is used for the comparison.
a The access time of the file reference
B The birth time of the file reference
c The inode status change time of reference
m The modification time of the file reference
t reference is interpreted directly as a time
Some combinations are invalid; for example, it is invalid for X to be t. Some combinations are not implemented on all systems; for example B is not
supported on all systems. If an invalid or unsupported combination of XY is specified, a fatal error results. Time specifications are interpreted as
for the argument to the -d option of GNU date. If you try to use the birth time of a reference file, and the birth time cannot be determined, a fatal
error message results. If you specify a test which refers to the birth time of files being examined, this test will fail for any files where the
birth time is unknown.
Try the following command:
find /var/tmp -mtime +2 -a -mtime -8 -ls
This will allow you to find files in /var/tmp folder that are older than 2 days but not older than 8 days.
Some good solutions on here. Wanted to share mine as well as it is short and simple.
I'm using find (GNU findutils) 4.5.11
$ find search/path/ -newermt 20130801 \! -newermt 20130831
You can use the below to find what you need.
Find files older than a specific date/time:
find ~/ -mtime $(echo $(date +%s) - $(date +%s -d"Dec 31, 2009 23:59:59") | bc -l | awk '{print $1 / 86400}' | bc -l)
Or you can find files between two dates. First date more recent, last date, older. You can go down to the second, and you don't have to use mtime. You can use whatever you need.
find . -mtime $(date +%s -d"Aug 10, 2013 23:59:59") -mtime $(date +%s -d"Aug 1, 2013 23:59:59")
Use stat to get the creation time. You can compare the time in the format YYYY-MM-DD HH:MM:SS lexicographically.
This work on Linux with modification time, creation time is not supported. On AIX, the -c option might not be supported, but you should be able to get the information anyway, using grep if nothing else works.
#! /bin/bash
from='2013-08-01 00:00:00.0000000000' # 01-Aug-13
to='2013-08-31 23:59:59.9999999999' # 31-Aug-13
for file in * ; do
modified=$( stat -c%y "$file" )
if [[ $from < $modified && $modified < $to ]] ; then
echo "$file"
fi
done
You can use the following commands to list files between 2 specific dates:
Search on current (.) directory:
find . -type f -newermt "2019-01-01" ! -newermt "2019-05-01"
Search on /var/any/directory/ directory:
find /var/any/directory/ -type f -newermt "2019-01-01" ! -newermt "2019-05-01"
Script oldfiles
I've tried to answer this question in a more complete way, and I ended up creating a complete script with options to help you understand the find command.
The script oldfiles is in this repository
To "create" a new find command you run it with the option -n (dry-run), and it will print to you the correct find command you need to use.
Of course, if you omit the -n it will just run, no need to retype the find command.
Usage:
oldfiles [-v...] ([-h|-V|-n] | {[(-a|-u) | (-m|-t) | -c] (-i | -d | -o| -y | -g) N (-\> | -\< | -\=) [-p "pat"]})
Where the options are classified in the following groups:
Help & Info:
-h, --help : Show this help.
-V, --version : Show version.
-v, --verbose : Turn verbose mode on (cumulative).
-n, --dry-run : Do not run, just explain how to create a "find" command
Time type (access/use, modification time or changed status):
-a or -u : access (use) time
-m or -t : modification time (default)
-c : inode status change
Time range (where N is a positive integer):
-i N : minutes (default, with N equal 1 min)
-d N : days
-o N : months
-y N : years
-g N : N is a DATE (example: "2017-07-06 22:17:15")
Tests:
-p "pat" : optional pattern to match (example: -p "*.c" to find c files) (default -p "*")
-\> : file is newer than given range, ie, time modified after it.
-< : file is older than given range, ie, time is from before it. (default)
-= : file that is exactly N (min, day, month, year) old.
Example:
Find C source files newer than 10 minutes (access time) (with verbosity 3):
oldfiles -a -i 10 -p"*.c" -\> -nvvv
Starting oldfiles script, by beco, version 20170706.202054...
oldfiles -vvv -a -i 10 -p "*.c" -\> -n
Looking for "*.c" files with (a)ccess time newer than 10 minute(s)
find . -name "*.c" -type f -amin -10 -exec ls -ltu --time-style=long-iso {} +
Dry-run
Find H header files older than a month (modification time) (verbosity 2):
oldfiles -m -o 1 -p"*.h" -\< -nvv
Starting oldfiles script, by beco, version 20170706.202054...
oldfiles -vv -m -o 1 -p "*.h" -\< -n
find . -name "*.h" -type f -mtime +30 -exec ls -lt --time-style=long-iso {} +
Dry-run
Find all (*) files within a single day (Dec, 1, 2016; no verbosity, dry-run):
oldfiles -mng "2016-12-01" -\=
find . -name "*" -type f -newermt "2016-11-30 23:59:59" ! -newermt "2016-12-01 23:59:59" -exec ls -lt --time-style=long-iso {} +
Of course, removing the -n the program will run the find command itself and save you the trouble.
I hope this helps everyone finally learn this {a,c,t}{time,min} options.
The LS output:
You will also notice that the ls option ls OPT changes to match the type of time you choose.
Link to clone/download of the oldfiles script:
https://github.com/drbeco/oldfiles
Explanation: Use unix command find with -ctime (creation time) flag.
The find utility recursively descends the directory tree for each path listed, evaluating an expression (composed of the 'primaries' and 'operands') in terms of each file in the tree.
Solution: According to official documentation:
-ctime n[smhdw]
If no units are specified, this primary evaluates to true if the difference
between the time of last change of file status information and the time find
was started, rounded up to the next full 24-hour period, is n 24-hour peri-
ods.
If units are specified, this primary evaluates to true if the difference
between the time of last change of file status information and the time find
was started is exactly n units. Please refer to the -atime primary descrip-
tion for information on supported time units.
Formula:
find <path> -ctime +[number][timeMeasurement] -ctime -[number][timeMeasurment]
Examples:
1.Find everything that were created after 1 week ago and before 2 weeks ago.
find / -ctime +1w -ctime -2w
2.Find all javascript files (.js) in current directory that were created between 1 day ago to 3 days ago.
find . -name "*\.js" -type f -ctime +1d -ctime -3d

Find files created 30 minutes before AND after a given file - UNIX

I am trying to figure out the command to display all files created 30 minutes (as an example) before and after another file was created. So far I managed to find files newer than that file
but I cannot work out how to look for both before and after given time.
A command I have used:
find -type f -newer file.txt -cmin -30
This works fine but only does half of what I am trying to do.
Also, I need to modify that to search for setuid files only, which I THINK I can do by adding the -perm -4000 in that command.
Any suggestions?
As far as I know there is no way to find file creation time.
You can try by modification time (this will get all files last-modified between 5th and 8th)
find . -type f -newermt 2012-10-05 ! -newermt 2012-10-08
(or access time replace newermt with newerat)
newerXY is flag to compare timestamps of current file with reference (see man find for more info).
According to man find (on my debian) there are 4 flags (aside from t to interpret directly as time)
a The access time of the file reference
B The birth time of the file reference
c The inode status change time of reference
m The modification time of the file reference
You can also try with 'B' birth time but it does not work for me, gives me error. I don't know why it is included in the man page
compare to another file
find / -newer file
find / ! -newer file
You can create temp file (one with modification time 30 min before the target file, another 30 mins after)
touch -d `stat -c %y test.txt` - 30 temp/before_temp
touch -d `stat -c %y test.txt` + 30 temp/after_temp
find / -newer temp/before_temp ! -newer temp/after_temp
touch -d takes a date option, so if you add and subtract correctly, this should work.

Finding files modified within an hour of another file

If i have 3 files called 1.txt,2.txt and 3.txt for example and they were created an hour apart, say 1pm 2pm and 3pm respectively. What I need is a command that finds all files modified within an hour of a specific file.
I'm in the same directory as the files in the terminal and all files are setuid permission
I've been trying:
find . -type f -perm -4000 -newer 2.txt -mmin -60 -print
This should return 3.txt but it doesn't
What would use to file created in the hour before or after 2.txt?
Try this
touch /tmp/temp -t time1
touch /tmp/ntemp -t time2
find . -newer /tmp/temp -a ! -newer /tmp/ntemp -exec ls -l {} \; 2>/dev/null
where
time1 = time of file creation - 1hr
time2 = time of file creation + 1hr
Ex:
time1 = 201210041500
time2 = 201210041700
Here is my logic -
First get time of last access of file in seconds since Epoch in some variable.
time_in_sec=$(stat -c %X 2.txt)
Get the time of last hour ( ie 3600 seconds back )
one_hr_old_time_in_sec=`expr $time_in_sec - 3600`
Convert it into format suitable for find command
newerthan=$(date -d #$one_hr_old_time_in_sec '+%m-%d-%y%n %H:%M:%S')
Convert time of original file in format suitable for find command
olderthan=$(date -d #$time_in_sec '+%m-%d-%y%n%H:%M:%S')
Get the list of files modified between two time periods using find command
find . -newermt "$newerthan" ! -newermt "$olderthan" -print
If it works you can write a small shell script which will take file name as parameter and can try for +3600 also.
Honestly, I haven't tried it. Hope it works !
The previous solution can be simplified since -newermt shall accept the same formats than 'date' including #N for N seconds since epoch.
Also for the 'stat' command it is probably better to use -Y (the time of last modification) instead of -X (the time of last access).
So the command to find the files modified + or - 1 hours of 2.txt is
N=$(stat -c %Y 2.txt)
find . -newermt #$((N-3600)) ! -newermt #$((N+3600)) -print
If you are running this after 4pm, given your example, it makes sense that it wouldn't return 3.txt, as -newer 2.txt -mmin -60 means "modified in the last 60 minutes, and more recently than 2.txt", not "modified less than 60 minutes after 2.txt". I don't think find currently has options to do what you're wanting (at least, the version I have doesn't), but it shouldn't be too hard to script in python or perl.

Finding files by creation time of another file

What I need to do is find files by the creation time of another file. For example if i create a file at 9am and later i wanted to find all the files created 1 hour after it or 1 hour before it. How would i do that?
I've tried experimenting with "-newer" whilst using "find" but I think "xargs" is what i need to be using.
Thanks
I know this is ooooold, but since I was looking for the same thing...
Here's a oneliner version, basically using the same approach as above:
Modified at least one hour after:
find . -newermt "$(date -d "$(stat -c %y reference_file) + 1 hour")"
Modified one hour before or more:
find . -not -newermt "$(date -d "$(stat -c %y reference_file) - 1 hour")"
Modified within the timespan from one hour before to one hour after
find . -newermt "$(date -d "$(stat -c %y reference_file) - 1 hour")" -not -newermt "$(date -d "$(stat -c %y reference_file) + 1 hour")"
Replace reference_file with the file of your choice. You can of course also use othe timespans than 1 hour
How it works
stat -c %y reference_file will return the modification time.
date -d "[...] + 1 hour" will manupulate the date string to one hour later.
find . -newermt "[...]" will find files with modification time (m) newer than given time (t)
All this requires GNU find 4.3.3 or greater (for -newerXY) and GNU date (to support -d and the complex date strings)
After looking at this I found a way to do this, although it is not the nicest solution as it requires integer arithmetic to be done on time.
The idea is to take the seconds since Unix epoch (aka Unix time) from your reference file, do some integer arithmetic on this to get your offset time (one hour before, or after in your example). Then you use find with the -newer parameter.
Example code:
# Get the mtime of your reference file in unix time format,
# assumes 'reference_file' is the name of the file you're using as a benchmark
reference_unix_time=$(ls -l --time-style=+%s reference_file | awk '{ print $6 }')
# Offset 1 hour after reference time
let unix_time_after="$reference_unix_time+60*60"
# Convert to date time with GNU date, for future use with find command
date_time=$(date --date #$unix_time_after '+%Y/%m/%d %H:%M:%S')
# Find files (in current directory or below)which are newer than the reference
# time + 1hour
find . -type f -newermt "$date_time"
For your example of file created upto one hour before the reference file you could use
# Offset 1 hour before reference time
let unix_time_before="$reference_unix_time-60*60"
# Convert to date time with GNU date...
date_time=$(date --date #$unix_time_before '+%Y/%m/%d %H:%M:%S')
# Find files (in current directory or below which were generated
# upto 1 hour before the reference file
find . -type f -not -newermt "$date_time"
Note that all the above is based on the last modification time of files.
The above has been tested with GNU Find (4.5.10), GNU Date (8.15) and GNU Bash (4.2.37).

Resources