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'
同じリストを生成します。これは通常は動作しますが、常に動作するとは限りません。それでも、テストで生成されたファイルがタイムスタンプファイルよりも古いと表示されるという状況になります。
ありがとう!
PSこれを別の方法で実現するには、ディレクトリの2つのスナップショットを作成します。1つはテストプログラムの実行前、もう1つは実行後、比較します。最初のリストにない2番目のリストのファイルはすべて、テストプログラムによって作成されている必要があります(バックグラウンドジョブや、dirに書き込む他のユーザーは関係ありません)。ただし、テストを実行する前に出力ファイルが削除されなかった場合(そうであるはずですが、場合によっては削除されない可能性があります)、このメソッドは、テストプログラムが実行される前にディレクトリにあったためです。
解決
実行前にすべてのファイルのファイル名を取得しますが、タイムスタンプを含めます。
find -printf '%p %T@\n' | sort > file1
その検索オプションを使用できない場合は、そのジョブにもstatを使用できます。
find -print0 | xargs -0 stat -c "%n %Y" | sort > file1
そしてfile2
への実行後。次に使用
comm -1 -3 file1 file2
そして、%T@
に固有の行が表示されます。これは、間違っていない場合は新しいファイルでなければなりません。以前に存在していた場合、変更時間は変更されます。これは、<=> thingy(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]$`
他のヒント
実際にtouchを使用して、ディレクトリ内の現在のすべてのファイルのタイムスタンプを次のように強制的に過去のものにすることができます。
touch -t 200801010000.00 *
テストを実行する前にこれを行うと、<!> quot; find -newer
<!> quot;の時間に十分な差があるはずです。それを拾う。粒度が2分であれば、現在のすべてのファイルを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が適切にインストールされていると仮定すると、<!> quot; date -t
<!> quot;の正しい形式で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
同じ効果がありますが、コーヒーを飲むのに10分かかります(または、コーヒーを飲む人でない場合は選択した毒)。
find(1)
の実装方法を検討すると、これが期待どおりに機能しない場合があることが明らかになります。ヒントを次に示します。
$ touch timestamp ; touch newer ; find . -newer timestamp
$ rm timestamp newer
$ touch timestamp ; sleep 1 ; touch newer ; find . -newer timestamp
.
./newer
$
stat(2)
は、システムコールstruct stat
を使用してファイルmtime / ctime / atimeの値を取得します。 <sys/stat.h>
からのtime_t
の要素は次のとおりです(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(および一般的にユニックス)では、-newer
は<!> quot; 1970年の開始からの秒数<!> quot;を表す整数です。したがって、<=>で理解できる最も細かい粒度はわずか1秒です。
テストを実行する一時ディレクトリを作成しないのはなぜですか?ディレクトリでタイムスタンプベースの名前を使用して、どの結果がいつ発生したかを追跡し、終了したらディレクトリ全体を削除します。