Условия гонки меток времени создания файлов в Linux

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

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

Оказывается, гранулярность find -newer оставляет желать лучшего, поэтому обычно случается, что некоторые файлы, созданные тестовой программой, отображаются как СТАРШЕ, чем файл с отметкой времени. Итак, я попробовал это:

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

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

Спасибо!

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
2 978
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

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

Собственно просто поставить usleep 500000 после тачка работает, но вроде коряво. Весь пакет занимает много времени, поэтому добавление таких задержек проблематично. Большинство тестов занимают 10-60 секунд. для запуска, поэтому нет состояния гонки. Но тест, который занимает доли секунды, вызывает проблемы.

Dave Wade-Stein 03.01.2009 02:53

Ваше первое решение убедительно. Нет никакой реальной проблемы с изменением временных меток, поэтому я могу установить их, как вы описали. Too bad touch -t не принимает в качестве аргумента «секунды с 1970 года». знак равно

Dave Wade-Stein 03.01.2009 02:55

@Dave, при условии, что у вас установлен Perl, материал Date :: Manip из CPAN должен довольно легко преобразовывать временные метки UNIX в строки и из них.

paxdiablo 03.01.2009 03:11

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

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

Dave Wade-Stein 03.01.2009 02:50

Как известно, детализация временных меток нестандартна. Просто: mkdir tmp (cd tmp # ссылочные файлы в .. а не.) Rm -Rf tmp

pixelbeat 03.01.2009 03:44
Ответ принят как подходящий

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

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

If you haven't got that find option available, you can use stat for that job too:

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]$`

Это круто. Я думал, что решение состоит в том, чтобы объединить два моих метода, но я бы использовал неуклюжую 'ls -l' и полностью забыл о comm (я никогда не был так знаком с этим, но теперь я). БЛАГОДАРНОСТЬ!

Dave Wade-Stein 03.01.2009 08:38

Оказалось, что find не работает таким образом в Darwin (Mac OS), поэтому я вернулся к использованию ls -l, потому что мне нужно, чтобы он работал на многих платформах, но ваше решение по-прежнему для меня лучшее. Спасибо!

Dave Wade-Stein 04.01.2009 07:31

Дэйв Уэйд-Штайн, вы можете использовать stat вместо find. find -print0 | xargs -0 stat -c "% n% Y". может это есть в наличии?

Johannes Schaub - litb 04.01.2009 12:33

Если вы рассмотрите, как реализован 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, составляет всего одну секунду.

Другие вопросы по теме