Compare two file modification dates

filesstattimestamps

I am creating a generic compilation/transpilation system. One way to know if a file has been compiled/transpiled already would be to compare the source and target file modification dates.

I need to write a bash script that can do that:

source_file=foo;
target_file=bar;

stat_source=$(stat source_file);
stat_target=$(stat target_file);

but how can I extract the dates from the stat output and compare them? Is there a better way than stat to compare the most recent modification time of a file?

If I call stat on a log file, I get this:

16777220 12391188 -rw-r--r-- 1 alexamil staff 0 321 "Jun 22 17:45:53 2017" "Jun 22 17:20:51 2017" "Jun 22 17:20:51 2017" "Jun 22 15:40:19 2017" 4096 8 0 test.log

AFAICT, the time granularity is no finer than seconds. I need to get something more granular than that if possible.

Best Answer

In testing on this linux system. The usual way to test file times is the shell:

[ file1 -nt file2 ] && echo "yes"

Seems to work with seconds. This, which will touch the files with a time difference less than a second, doesn't detect that difference:

$ touch file2; sleep 0.1; touch file1; [ file1 -nt file2 ] && echo "yes"

To confirm the issue (time after the dot is nanoseconds):

$ ls --time-style=full-iso -l file?
-rw-r--r-- 1 user user 0 2017-06-23 01:37:01.707387495 -0400 file1
-rw-r--r-- 1 user user 0 2017-06-23 01:37:01.599392538 -0400 file2

The file1 is (a bit) newer than file2.

The problem now will be to correctly process the time value.

One solution is to use a formatted output of ls:

$ ls --time-style=+%s.%N -l file?
-rw-r--r-- 1 user user 0 1498196221.707387495 file1
-rw-r--r-- 1 user user 0 1498196221.599392538 file2

Extracting the time to two variables (without the dot):

$ file1time=$(ls --time-style=+%s%N -l file1 | awk "{print(\$6)}")
$ file2time=$(ls --time-style=+%s%N -l file2 | awk "{print(\$6)}")

And compare the times (times with nanoseconds just barely fit in a 64 bit value. If your system does not use 64 bit, this comparison will fail):

$ [ $file1time -gt $file2time ] && echo "yes"
yes

That shows that file1 is newer than file2


If ls fails to have the format needed, then you may try stat.

$ stat file1
  File: file1
  Size: 0               Blocks: 0          IO Block: 4096   regular file
Device: 805h/2053d      Inode: 9180838     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/    user)   Gid: ( 1000/    user)
Access: 2017-06-23 01:37:01.707387495 -0400
Modify: 2017-06-23 01:37:01.707387495 -0400
Change: 2017-06-23 01:37:01.707387495 -0400
 Birth: -

If the output shows nanoseconds, the we will need date to parse (and format) the time.

$ stat --printf='%y\n' file1
2017-06-23 01:37:01.707387495 -0400

$ date +'%s%N' -d "$(stat --printf='%y\n' file1)" 
1498196221707387495

The rest is the same, assign the results of file1 and file2 to two variables and numerically compare them.