Условие гонки отметки времени создания файла Linux - PullRequest
3 голосов
/ 03 января 2009

Я пытаюсь сделать то, что мне кажется простым в Linux. У меня есть скрипт bash, который запускает различные тестовые программы, и я хочу определить, какие файлы в текущем каталоге были созданы тестовыми программами. Поэтому я делаю что-то вроде этого:

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

Оказывается, гранулярность find -newer плохая, поэтому обычно происходит то, что некоторые файлы, сгенерированные тестовой программой, отображаются как OLDER, чем файл метки времени. Тогда я попробовал это:

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

для создания того же списка. Это обычно работает, но не всегда. Я все еще сталкиваюсь с ситуацией, когда файлы, сгенерированные тестом, отображаются как более старые, чем файл метки времени.

Спасибо!

P.S. Я могу сделать это другим способом, сделав два снимка каталога, один до запуска тестовой программы, а затем один после, и сравнив их. Любые файлы во втором списке, которых нет в первом, должны быть созданы тестовой программой (меня не интересуют фоновые задания или другие пользователи, пишущие в каталог). Но этот метод не тот, который я хочу, потому что, если выходной файл не был удален до запуска теста (они должны быть, но в некоторых случаях они могут не быть), этот метод скажет, что он не был создан тестовая программа, потому что она была в директории до запуска тестовой программы.

Ответы [ 4 ]

3 голосов
/ 03 января 2009

На самом деле вы можете использовать touch, чтобы принудительно установить временные метки всех текущих файлов в каталоге, такие как:

touch -t 200801010000.00 *

Если вы сделаете это перед запуском теста, разницы во времени должно быть более чем достаточно, чтобы "find -newer" поднял его. Если гранулярность составляла две минуты, вы можете установить для всех текущих файлов десять минут назад, для файла отметки времени - 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, вы можете сделать следующее, чтобы получить 5 минут назад (или использовать -600 в течение 10 минут) в правильном формате для "date -t":

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

, который имеет тот же эффект, но дает вам десять минут, чтобы пойти выпить кофе (или ваш предпочтительный яд, если вы не пьющий кофе).

2 голосов
/ 03 января 2009

Если вы рассмотрите, как реализован find(1), будет понятно, почему это иногда может работать не так, как вы ожидаете. Вот подсказка:

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

find(1) получает значения файла mtime / ctime / atime с помощью системного вызова stat(2). Вот элементы struct stat из <sys/stat.h> (Linux):

  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 (и вообще в Unix) time_t - это целое число, обозначающее «секунды с начала 1970 года». Поэтому лучшая гранулярность, которую может понять -newer, составляет всего одну секунду.

1 голос
/ 03 января 2009

Возьмите имена файлов всех файлов перед запуском, но включите их временные метки:

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

Если у вас нет этой опции поиска, вы также можете использовать stat для этой работы:

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]$`
0 голосов
/ 03 января 2009

Почему бы не создать временный каталог для запуска тестов? Используйте основанное на временной метке имя в каталоге, чтобы отслеживать, когда произошли результаты, и просто удалите весь каталог, когда закончите.

...