web-dev-qa-db-ja.com

ファイルが書き込み中かどうかを確認しますか?

特定のディレクトリでtarファイルを探す自動化プロセスを(1分のcronスクリプトを介して)展開する必要があります。 tarファイルが見つかると、適切な場所に展開され、tarファイルは削除されます。

Tarファイルは、別のサーバーからSSH経由でこのサーバーに自動的にコピーされます。場合によっては、tarファイルは非常に大きく、多数のファイルがあります。

私が実行することを期待している問題:tarファイルがサーバーにコピーされるのに1分以上かかり、cronスクリプトが毎分1回実行される場合、.tar.gzファイルを確認して実行しようとしますtarファイルがまだ書き込まれている最中でも、それをuntarします。

ファイルが現在書き込まれているのか、それが部分的なファイルだけであるのかなどをテストする方法はありますか(bashコマンドを介して)?

私が考えていた1つの代替案は、ファイルを別のファイル拡張子(.tar.gz.partなど)としてコピーし、転送の完了後に.tar.gzに名前を変更することでした。しかし、私は、ファイルがコマンドラインで完全であるかどうかを最初に判断する方法があるかどうかを考えようと考えました...手がかりはありますか?

27
Jake Wilson

あなたは正しい軌道に乗っています。ファイルの名前を変更することはアトミック操作であるため、アップロード後に名前を変更することはシンプルでエレガントで、エラーが発生しにくくなっています。私が考えることができる別のアプローチは、lsof | grep filename.tar.gzは、ファイルが別のプロセスによってアクセスされているかどうかを確認します。

12
Alex

あなたの最善の策は、lsofを使用して、ファイルがプロセスによって開かれているかどうかを判断することです。

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

書き込み中かどうかは簡単にはわかりませんが、書き込み中の場合は開いている必要があります。


編集:提案されたソリューションを実装するのではなく、ここで実際の問題を解決しましょう!

Rsyncを使用してファイルを転送します。

○ → rsync -e ssh remote:big.tar.gz .

この方法では、ファイルは既存のファイルの上にコピーされませんが、一時ファイル(.big.tar.gz.XXXXXX)転送が完了するまで、その後所定の場所に移動します。

15
MikeyB

少し古いですが、ほとんどの回答は質問の要点を完全に逃しています。

しかし、私は最初にファイルがコマンドラインで完全であるかどうかを判断する方法があるかどうかを理解しようとするだろうと考えました...

一般的にはありません。それを判断するのに十分な情報がありません。

ファイルがclosedであると判断することは、ファイルがwholeであるかどうかを判断することと同じではないためです。たとえば、転送の途中で接続が失われた場合、ファイルは「クローズ」されます。

@Alexの答えだけがこの問題を解決しました。そして彼はlsofをいくらか使用することに失敗しました。

ファイルが完全に転送されたかどうかを確認するには、正常に転送するにはさらにデータが必要です。といった:

私が考えていた1つの代替案は、ファイルを別のファイル拡張子(_.tar.gz.part_など)としてコピーし、転送が完了した後で_.tar.gz_に名前を変更することでした。

これは、ファイルが完全に正常に転送されたことを伝えるための完全に優れた方法です。同じファイルシステム内にいる限り、ディレクトリ間でファイルを移動することもできます。または、送信者に空の_filename.done_ファイルを送信して完了を知らせます。

しかし、すべての方法は、転送が正常に完了したことを何らかの方法で通知する送信者に依存する必要があります。送信者だけがその情報を持っているからです。

一部のファイル形式(PDFなど)には、ファイルが完全であるかどうかを判別できるデータが含まれています。しかし、見つけるには、ファイル全体を開いて読み取る必要があります。

lsofは、ファイルが開いていないことを通知するだけです-通知されません理由開いていない。また、ファイルの大きさが想定される大きさもわかりません。

6
Andrew Henle

これを行う最善の方法は、 incron ( "inotify cron system")を使用することです。 inotify ウォッチをディレクトリに設定して、ファイル操作を通知することができます。この場合、dirでclose_writeを監視する必要があります。これにより、書き込み後にファイルが閉じられたら、コマンドを実行できます。

5
Kyle

Lsofはファイルが開いているモードを検出できるようです:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

1wと書かれている場所を参照してください。つまり、ファイル記述子番号は1で、モードはw、つまり書き込みです。

2
Kevin Baragona

inotifywaitを使用すると、目的を達成できます。コマンドを実行する前に、ファイルの書き込みが完了するまで待機することができます。

以下は、新しいファイルのフォルダーを継続的に監視し、ファイルへの書き込みが完了したときにループ内でコマンドを実行します。

WATCH_DIR=/directory/to/monitor
DEST_DIR=/x/y/z

/usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do

mv "$0" "$DEST_DIR"

done

その他の設定オプションについては https://linux.die.net/man/1/inotifywatch を参照してください

0
teeedubb