"find command -mtime 0" not getting the file i expect - unix

I am trying to find a file that are 0 days old. Below are the steps I performed to test this
$ ls
$ ls -ltr
total 0
$ touch tmp.txt
$ ls -ltr
total 0
-rw-r----- 1 tstUser tstUser 0 Feb 28 20:02 tmp.txt
$ find * -mtime 0
$
$ find * -mtime -1
tmp.txt
$
Why is '-mtime 0' not getting me the file?
What is the exact difference between '-mtime 0' and '-mtime -1'?
Im sure there must be other ways to find files that are 0 days old in unix, but im curious in understanding how this '-mtime' actually works.

This is a not user friendly aspect of find - you have to understand how the matching actually works to correctly define your search criteria. The following explanation is based on GNU find (findutils) 4.4.2.
find tests -atime, -ctime, -mtime work on 24 hour periods, therefore let's define "file age" as
floor (current_timestamp - file_modification_timestamp / 86400)
Given three files modified 1 hour ago, 25 hours ago and 49 hours ago
$ touch -t $(date -d "1 hour ago" +"%m%d%H%M") a.txt
$ touch -t $(date -d "25 hours ago" +"%m%d%H%M") b.txt
$ touch -t $(date -d "49 hours ago" +"%m%d%H%M") c.txt
file ages (as defined above) are
$ echo "($(date +"%s") - $(stat -c %Y a.txt)) / 86400" | bc
0
$ echo "($(date +"%s") - $(stat -c %Y b.txt)) / 86400" | bc
1
$ echo "($(date +"%s") - $(stat -c %Y c.txt)) / 86400" | bc
2
Given the above, here's what find does
$ find -type f -mtime 0 # find files with file age == 0, i.e. files modified less than 24 hours ago
./a.txt
$ find -type f -mtime -1 # find files with file age < 1, i.e. files modified less than 24 hours ago
./a.txt
$ find -mtime 1 # find files with file age == 1, i.e. files modified more than (or equal to) 24 hours ago, but less than 48 hours ago
./b.txt
$ find -mtime +1 # find files with file age > 1, i.e. files modified more than 48 hours ago
./c.txt
This shows that -mtime 0 and -mtime -1 give equivalent results.
-mmin gives the same test with finer granularity - argument is minutes instead of 24 hour periods.
I'm unable to reproduce your problem using the aforementioned version of find
$ touch tmp.txt
$ find * -mtime 0
tmp.txt
$ find * -mtime -1
tmp.txt

-mtime n
File's data was last modified n*24 hours ago. See the comments
for -atime to understand how rounding affects the interpretation
of file modification times.
So, -mtime 0 would be equal to: "File's data was last modified 0 hours ago.
While -mtime 1 would be: "File's data was last modified 24 hours ago"
Edit:
Numeric arguments can be specified as
+n for greater than n,
-n for less than n,
n for exactly n.
So I guess -1 would be modified within the last 24 hours, while 1 would be exactly one day.

The meaning of those three possibilities are as following:
n: exactly n 24-hour periods (days) ago, 0 means today.
+n: "more then n 24-hour periods (days) ago", or older then n,
-n: less than n 24-hour periods (days) ago (-n), or younger then n. It's evident that -1, and 0 are the same and both means "today".
NOTE: If you use parameters with find command in scripts be careful when -mtime parameter is equal zero. Some (earlier) versions of GNU find incorrectly interpret the following expression
Sourece: http://www.softpanorama.org/Tools/Find/index.shtml

Related

Distorted output while reading in the fast appending logs using Tail in Unix

I am using a tail function to read close to 460 log files which keep appending all at the same time. The data I am trying to read is byte separated fixed width.Please find below the command I use:
find ###Directory### -mmin -2 -type f -name FileNameString*.log | xargs tail -qf -n -1
The expected format of log files is given below:
KS0A2018020723594007G58P5CNSSHAGPRGGWS G NH 0962201803061535PEK HND C 999 9 9CC91 990C 900 99
KS0A2018020723594007G58P5CNSSHAGPRGGWS G NH 5702201803060910PEK NRT C 444 0 4 0 40 00 44
but the format I see in the output is as below:
KS0A2018020723594912V1KY7USSCNTNPRAAPI P AA 3735201802111632IAH OR3903G7YI0HKSQUNAPRAAPI P AA 1583201812241935DEN DFW P 7 7 777777777 7 7 7 7
KS0A2018020723593952G56SCKRSGKORPRGFLCNG AZ 0758201809301515FCO ICN P07100007017070010 00 7007
The tail function is distorting the way files are being read.
Any guidance in reading the format right using tail or any equivalent command will greatly help.
You need the -z option for tail.
$ find /path/to/ -mmin -2 -type f -name FileNameString*.log | xargs tail -qf -z -n -1
-z, --zero-terminated
line delimiter is NUL, not newline
Better to use, -exec for find
$ find /path/to/ -mmin -2 -type f -name "FileNameString*.log" -exec tail -qf -z -n -1 {} \+
If we do an Xargs without assigning arguments to the Xargs, there will always be distortion in the output (as it tends to distort the line formation).
So,
find ###Directory### -mmin -2 -type f -name FileNameString*.log | xargs tail -qf -n -1
will always lead to distorted output as there is no controlled way to read in or write the output.
However, if we can pass the input variables to Xargs in a controlled manner by using -I, it was functioning well. In my case,
find ###Directory### -mmin -2 -type f -name FileNameString*.log | xargs -I% tail % -qf -n -1
produced the output format I expected. However, this can be a on the slower side of execution if the variable list to be passed to Xargs is lengthy.

How can I find the current date minus seven days in Unix?

I am trying to find the date that was seven days before today.
CURRENT_DT=`date +"%F %T"`
diff=$CURRENT_DT-7
echo $diff
I am trying stuff like the above to find the 7 days less than from current date. Could anyone help me out please?
GNU date will to the math for you:
date --date "7 days ago"
Other version will require you to covert the current date into seconds since the UNIX epoch first, manually subtract 7 days' worth of seconds, and convert that back into the desired form. Consult the documentation for your version of date for details on how to convert to and from Unix timestamps. Here's an example using GNU date again:
x=$(date +%s)
x=$((x - 7 * 24 * 60 * 60))
date --date #$x
Here is a simple Perl script which (unlike the other examples) works with Unix:
perl -e 'use POSIX qw(ctime); printf "%s", ctime(time - (7 * 24 * 60 * 60));'
(Tested with Solaris 10, and a token Linux system, of course - with the caveat that Perl is not necessarily part of one's configuration, merely very likely).
Adding this one for shells on OSX:
date -v-7d
> Tue Apr 3 15:16:31 EDT 2018
date
> Tue Apr 10 15:16:33 EDT 2018
Need that formated?
date -v-7d +%Y-%m-%d
> 2018-04-03
Ksh's printf can do time calculation:
$ printf '%(%Y-%m-%d)T\n'
2015-04-07
$ printf '%(%Y-%m-%d)T\n' '7 days ago'
2015-03-31
$
I haven't used unix in a while but I found this in one of my scripts
echo `date +%s`-604800 | bc
DATE=$(date --date "7 days ago" | awk '{print$1,$2,$3}')
echo "$DATE"
if [ -z "$(grep -i "$DATE" test.log)" ]; then
exit 1
fi
sed -i "1,/$DATE/d" test.log

How to list the files greater than specific timestamp in its pattern in Unix?

Can you please how I can accomplish the below scenario in Unix Ksh command?
I have a job J1 which is completed by the time HH:MM. I would like to list all the files created by this job J1, The file has the timestamp in its pattern YYYYMMDDHHMMSS_?
where YYYYMMDD is the date, HHMMSS is the system timestamp. I want to list the files if the job's timestamp is less than the file time stamp as the job creates the files, the timestamp of the job would be greater than the file timestamp?
Regards
Ben
You can use something like this: (Assuming the files listed)
$ ls -la
total 44K
drwxr-xr-x 2 gp users 4.0K Oct 27 14:56 .
drwxr-xr-x 11 gp users 4.0K Oct 27 14:57 ..
-rw-r--r-- 1 gp users 0 Oct 23 14:45 logfile
-rw-r--r-- 1 gp users 137 Oct 27 15:09 t2t2
prw-r--r-- 1 gp users 0 Oct 23 12:34 testpipe
-rw-r--r-- 1 gp users 0 Oct 23 14:51 tmpfile
-rw-r--r-- 1 gp users 7 Oct 27 14:58 ttt
# Find newer files
$ find . -newer ttt -print
./t2t2
# Find files that are NOT newer
$ find . ! -newer ttt -print
.
./tmpfile
./testpipe
./logfile
./ttt
# You can eliminate the directories (all of them) from the output this way:
$ find . ! -newer ttt ! -type d -print
./tmpfile
./testpipe
./logfile
./ttt
# or this way
$ find . ! -newer ttt -type f -print
Note that the different forms of the "newer" option (like anewer, cnewer) will not compare the other files against the the same timestamp. You might have to do a few tests to see which version suits you better.
If you must use the timestamp in the file name, and the different options of "find", including "mmin" are not acceptable, then you will have to examine the embedded timestamp of each file name. I suggest checking into these commands:
# You have to escape the < of > signs you use.
$ expr "fabc" \< "cde"
0
$ expr "abc" \< "cde"
1
and this:
FILENAME="ABC_20141026101112.log" ; TIMESTAMP="`expr \"$FILENAME\" : \".*_20\([0-9]\{12\}\).*$\"`";echo $TIMESTAMP
So a "while read" loop, looking at all the file names and comparing their timestamps using the above "expr" compares should do the job. Ideally, I'd try to see if "find" can do the job because reading and examining each file will be slower. If you have thousands of files in that directory, then I would try some other solution. If you are interested in more options, let me know.

Unix: Increment date column by one day in csv file

Help needed. I want to increment Date (which is a string) column in csv by one day.
e.g. (Date Format yyyy-MM-dd)
Col1,Col2,Col3
ABC,001,1900-01-01
XYZ,002,2000-01-01
Expected OutPut
Col1,Col2,Col3
ABC,001,1900-01-02
XYZ,002,2000-01-02
There's one standard Unix utility that has all the date magic from September 14, 1752 through December 31, 9999 built-in: the calendar cal. Instead of reinventing the wheel and do messy date calculations we will use its intelligence to our advantage. The basic problem is: given a date, is it the last day of a month? If not, simply increment the day. If yes, reset day to 1 and increment month (and possibly year).
However, the output of cal is unspecified and it may look like this:
$ cal 2 1900
February 1900
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28
What we would need is a list of days, 1 2 3 ... 28. We can do this by skipping everything up to the "1":
set -- $(cal 2 1900)
while test $1 != 1; do shift; done
Now the number of args gives us the number of days in February 1900:
$ echo $#
28
Putting it all together in a script:
#!/bin/sh
read -r header
printf "%s\n" "$header"
while IFS=,- read -r col1 col2 y m d; do
case $m-$d in
(12-31) y=$((y+1)) m=01 d=01;;
(*)
set -- $(cal $m $y)
# Shift away the month and weekday names.
while test $1 != 1; do shift; done
# Is the day the last day of a month?
if test ${d#0} -eq $#; then
# Yes: increment m and reset d=01.
m=$(printf %02d $((${m#0}+1)))
d=01
else
# No: increment d.
d=$(printf %02d $((${d#0}+1)))
fi
;;
esac
printf "%s,%s,%s-%s-%s\n" "$col1" "$col2" $y $m $d
done
Running it on this input:
Col1,Col2,Col3
ABC,001,1900-01-01
ABC,001,1900-02-28
ABC,001,1900-12-31
XYZ,002,2000-01-01
XYZ,002,2000-02-28
XYZ,002,2000-02-29
yields
Col1,Col2,Col3
ABC,001,1900-01-02
ABC,001,1900-03-01
ABC,001,1901-01-01
XYZ,002,2000-01-02
XYZ,002,2000-02-29
XYZ,002,2000-03-01
I made one little assumption: The first two columns don't contain a - or escaped comma. If they do, the IFS=,- read will act up.
Using the date command, this can be done in awk:
awk 'BEGIN{FS=OFS=","}NR>1{("date -d\""$3" +1 day\" +%Y-%m-%d")|getline newdate; $3=newdate; print}' file.in
If you can extract the date from the file, you can use this:
d="1900-01-01" # date from file
date --date '#'$(( $(date --date $d +"%s") + 86400 ))

Subtracting hex-valued file names

Using QNX Neutrino, I need to subtract hex-valued file names from their predecessors. The files are named by their creation time in hex. The following gets me a list of pure hex values, but I cannot subtrace them from eachother.
last=0
find /path/ -type f\(! iname ".*" \) -exec basename {} |
while read fname
do
current=$fname
echo "difference is $((current - last)) seconds
done
The find command gives me:
51b71f38
51b71f44
51b71f50
51b71f5c
51b71f74
I have tried using echo "ibase=16; $name" | bc but that only switches the value for the output. Is there a way to return an integer number which is the difference for these hex values?
May be something like this:
find /path/ -type f\(! iname ".*" \) -exec basename {} |
while read fname; do
last="$current"
current="$fname"
if [ $(( 0x$last )) -ne 0 ]; then
echo "difference is $(( 0x$current - 0x$last )) seconds"
fi
done
Test:
I used your find command as input from a file for the test.
$ cat ff
51b71f38
51b71f44
51b71f50
51b71f5c
51b71f74
$ while read fname; do last="$current" ; current="$fname" ; if [ $(( 0x$last )) -ne 0 ]; then echo "difference is $(( 0x$current - 0x$last )) seconds" ; fi ; done < ff
difference is 12 seconds
difference is 12 seconds
difference is 12 seconds
difference is 24 seconds
current=$(echo "ibase=16; $fname" |bc)
actually gives me the decimal value I needed inline

Resources