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





Фактически вы можете использовать касание, чтобы установить временные метки всех текущих файлов в каталоге в далекое прошлое, например:
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
который имеет тот же эффект, но дает вам десять минут, чтобы пойти выпить кофе (или ваш любимый яд, если вы не пьете кофе).
Ваше первое решение убедительно. Нет никакой реальной проблемы с изменением временных меток, поэтому я могу установить их, как вы описали. Too bad touch -t не принимает в качестве аргумента «секунды с 1970 года». знак равно
@Dave, при условии, что у вас установлен Perl, материал Date :: Manip из CPAN должен довольно легко преобразовывать временные метки UNIX в строки и из них.
Почему бы не создать временный каталог для запуска тестов? Используйте для каталога имя на основе метки времени, чтобы отслеживать, какие результаты произошли и когда, и просто удалите весь каталог, когда закончите.
Спасибо ... это разумное предложение. Проблема в том, что есть несколько ожиданий относительно того, какие файлы будут найдены в каталоге, и они могут быть разными для каждого теста. Поэтому я априори не знаю, какие входные файлы мне нужно скопировать во временный каталог. Я подумаю об этом еще немного ...
Как известно, детализация временных меток нестандартна. Просто: mkdir tmp (cd tmp # ссылочные файлы в .. а не.) Rm -Rf tmp
Возьмите имена файлов перед запуском, но включите их временные метки:
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 (я никогда не был так знаком с этим, но теперь я). БЛАГОДАРНОСТЬ!
Оказалось, что find не работает таким образом в Darwin (Mac OS), поэтому я вернулся к использованию ls -l, потому что мне нужно, чтобы он работал на многих платформах, но ваше решение по-прежнему для меня лучшее. Спасибо!
Дэйв Уэйд-Штайн, вы можете использовать stat вместо find. find -print0 | xargs -0 stat -c "% n% Y". может это есть в наличии?
Если вы рассмотрите, как реализован 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, составляет всего одну секунду.
Собственно просто поставить usleep 500000 после тачка работает, но вроде коряво. Весь пакет занимает много времени, поэтому добавление таких задержек проблематично. Большинство тестов занимают 10-60 секунд. для запуска, поэтому нет состояния гонки. Но тест, который занимает доли секунды, вызывает проблемы.