Linux文件创建时间戳竞争条件

时间:2009-01-02 23:19:06

标签: linux find timestamp

我正在尝试做我认为在Linux下很简单的事情。我有一个运行各种测试程序的bash脚本,我想确定当前目录中的哪些文件是由测试程序创建的。所以我正在做这样的事情:

touch timestamp-file
run the test
find -newer timestamp-file -type f > list-of-files
rm -f timestamp-file

结果发现-newer的粒度很差,所以通常会发生的情况是测试程序生成的某些文件显示为OLDER而不是timestamp文件。所以我试过这个:

ls -tr1 | sed '1,/timestamp-file/d'

生成相同的列表。这个通常有效,但并非总是如此。我仍然认为测试生成的文件显示为比timestamp文件旧的情况。

谢谢!

P.S。我可以通过获取目录的两个快照来实现另一种方式,一个在测试程序运行之前,一个之后,然后比较它们。第二个列表中不在第一个文件中的任何文件必须由测试程序创建(我不关心后台作业或写入目录的其他用户)。但是这个方法不是我想要的,因为如果在运行测试之前没有删除输出文件(它们应该是,但在某些情况下它们可能不是),这个方法会说它不是由测试程序,因为它在测试程序运行之前就在dir中。

4 个答案:

答案 0 :(得分:3)

您实际上可以使用touch强制将目录中所有当前文件的时间戳强制推迟到过去,例如:

touch -t 200801010000.00 *

如果您在运行测试之前执行此操作,“find -newer”获取它的时间应该有足够的差异。如果粒度为两分钟,则可以将所有当前文件设置为10分钟前,将时间戳文件设置为5分钟前,然后运行测试。

所以你的脚本变成了:

touch -t (current time - 10 minutes) *
touch -t (current time -  5 minutes) timestamp-file
run the test
find -newer timestamp-file -type f > list-of-files
rm -f timestamp-file

假设你有一个不错的Perl安装,你可以使用正确的“date -t”格式在5分钟前(或使用-600 10分钟)执行以下操作:

use Date::Manip;
print UnixDate(DateCalc(ParseDateString("now"),"-300"),"%Y%m%d%H%M.%S") . "\n";

如果出于某种原因,您不允许更改时间戳,请使用:

sleep 300
touch timestamp-file
sleep 300
run the test
find -newer timestamp-file -type f > list-of-files
rm -f timestamp-file

具有相同的效果,但是给你十分钟的时间去喝咖啡(或者如果你不是咖啡饮用者,你会选择你的毒药)。

答案 1 :(得分:2)

如果您考虑如何实施find(1),那么很明显为什么这有时可能无法按预期发挥作用。这是一个提示:

  $ touch timestamp ; touch newer ; find . -newer timestamp 
  $ rm timestamp newer
  $ touch timestamp ; sleep 1 ; touch newer ; find . -newer timestamp
  .
  ./newer
  $

find(1)使用系统调用stat(2)获取文件mtime / ctime / atime值。以下是来自struct stat(Linux)<sys/stat.h>的元素:

  time_t    st_atime;   /* time of last access */
  time_t    st_mtime;   /* time of last modification */
  time_t    st_ctime;   /* time of last status change */

在Linux上(通常是unices)time_t是一个表示“从1970年开始的秒数”的整数。因此,-newer可以理解的最细微的粒度只是一秒钟。

答案 2 :(得分:1)

在运行之前获取所有文件的文件名,但包括它们的时间戳:

find -printf '%p %T@\n' | sort > file1

如果您还没有找到该选项,您也可以使用该职位的统计数据:

find -print0 | xargs -0 stat -c "%n %Y" | sort > file1

跑到file2之后。然后使用

comm -1 -3 file1 file2

它会显示file2唯一的行,如果我没记错的话,必须是新文件。如果它们之前存在,它们的修改时间将会发生变化,这由%T@事物处理(打印出自1970年以来的秒数):

[js@HOST2 cpp]$ find -printf '%p %T@\n' | sort > file1
[js@HOST2 cpp]$ echo foo>bar
[js@HOST2 cpp]$ echo foo>baz
[js@HOST2 cpp]$ find -printf '%p %T@\n' | sort > file2
[js@HOST2 cpp]$ comm -1 -3 file1 file2
. 1230947309.0000000000
./bar 1230947308.0000000000
./baz 1230947309.0000000000
./file2 1230947315.0000000000
[js@HOST2 cpp]$ find -printf '%p %T@\n' | sort > file1
[js@HOST2 cpp]$ echo lol>bar
[js@HOST2 cpp]$ find -printf '%p %T@\n' | sort > file2
[js@HOST2 cpp]$ comm -1 -3 file1 file2
./bar 1230947359.0000000000
./file2 1230947362.0000000000
[js@HOST2 cpp]$`

答案 3 :(得分:0)

为什么不创建一个运行测试的临时目录?在目录上使用基于时间戳的名称来帮助跟踪发生的结果,并在完成后简单地删除整个目录。