Files

比較兩個文件修改日期

  • August 30, 2019

我正在創建一個通用編譯/轉譯系統。了解文件是否已經編譯/轉譯的一種方法是比較源文件和目標文件的修改日期。

我需要編寫一個可以做到這一點的 bash 腳本:

source_file=foo;
target_file=bar;

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

但是如何從 stat 輸出中提取日期並進行比較?有沒有比stat比較文件的最近修改時間更好的方法?

如果我在日誌文件上呼叫 stat ,我會得到:

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,時間粒度不小於秒。如果可能的話,我需要得到比這更細化的東西。

在這個linux系統上測試。測試文件時間的常用方法是 shell:

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

似乎與秒一起工作。這將接觸時間差小於一秒的文件,但不會檢測到該差異:

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

確認問題(點後的時間為納秒):

$ 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

file1(有點)新file2

現在的問題將是正確處理時間值。

一種解決方案是使用 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

將時間提取到兩個變數(不帶點):

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

並比較時間(納秒的時間幾乎不適合 64 位值。如果您的系統不使用 64 位,則此比較將失敗):

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

這表明它file1file2


如果ls無法獲得所需的格式,那麼您可以嘗試 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: -

如果輸出顯示納秒,我們將需要日期來解析(和格式化)時間。

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

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

其餘的都是一樣的,把file1和file2的結果賦值給兩個變數,數值比較。

鑑於您使用的是**stat**(類似的功能,但在 BSD 和 GNU 上的輸出格式不同),您還可以使用該test實用程序,它直接進行此比較:

  FILE1 -nt FILE2
         FILE1 is newer (modification date) than FILE2

  FILE1 -ot FILE2
         FILE1 is older than FILE2

在你的例子中,

if [ "$source_file" -nt "$target_file" ]
then
   printf '%s\n' "$source_file is newer than $target_file"
fi

該功能在 POSIX 中不可用(請參閱其文件test),它提供了一個基本原理:

一些新發明的或來自 KornShell 的額外初選作為條件命令的一部分出現在早期提案中(

$$ [ $$]):s1 >s2、s1 <s2、str = 模式、str != 模式、f1 **-nt**f2、f1 **-ot**f2 和 f1 -ef f2。當從 shell 中刪除條件命令時,它們沒有被帶到測試實用程序中,因為它們沒有包含在 sh 實用程序的歷史實現中內置的測試實用程序中。

不過,隨著該功能得到廣泛支持,這種情況在未來可能會發生變化。

請注意,當操作數是符號連結時,考慮的是符號連結目標的修改時間(這通常是您想要的,find -newer如果不是,則使用)。當符號連結無法解析時,實現之間的行為(有些人認為現有文件總是比無法解析的文件更新,如果任何操作數無法解析,有些人總是會報告錯誤)。

另請注意,並非所有實現都支持亞秒級粒度(bash’s test/ [builtin 從 4.4 版開始仍然不支持,例如,GNUtesttest內置的zshorksh93至少在 GNU/Linux 上)。

以供參考:

  • 對於 GNUtest實用程序實現(但請注意,您的 shell,iffish或 Bourne-like,也將有一個test/[內置通常隱藏它,使用env test而不是test繞過它),get_mtime在 test.c 中讀取struct timespec,並且
  • 選項**-nt**使用該數據

引用自:https://unix.stackexchange.com/questions/372857