ファイルの移動(閉じている場合のみ)

ファイルの移動(閉じている場合のみ)

外部プロセスによって生成された大容量ファイルを、外部プロセスが終了したらすぐに移動したいと思います。

このテストコマンドは正しいですか?

if lsof "/file/name"
then
        # file is open, don't touch it!
else
        if [ 1 -eq $? ]
        then
                # file is closed
                mv /file/name /other/file/name
        else
                # lsof failed for some other reason
        fi
fi

編集:ファイルはデータセットを表し、他のプログラムで作業できるようにファイルを移動するには完了するまで待つ必要があります。そのため、外部プロセスがファイルを完了したかどうかを知る必要があります。

答え1

lsofマニュアルページから

Lsofは、リストするように要求されたコマンド名、ファイル名、インターネットアドレス、またはファイル、ログイン名、NFSファイル、PID、PGID、またはUIDが見つからないなど、エラーが検出された場合は1を返します。 -V オプションが指定されている場合、lsof はリストに失敗した検索語を示します。

したがって、これはあなたのlsof failed for some other reason条件が決して実施されないことを示します。

外部プロセスでファイルが開いている間にファイルを移動してみましたか?ターゲットディレクトリが同じファイルシステム上にある場合は、3番目のプロセスの元のパスからアクセスする必要がある場合を除き、デフォルトのinodeは変更されていないため、これを行うことに問題はありません。そうでなければ、mvとにかく失敗すると思います。

外部プロセスがファイル処理を完了するのを待つ必要がある場合は、繰り返しポーリングする代わりにブロックコマンドを使用することをお勧めします。 Linuxではこれを使用できますinotifywait。たとえば、

 inotifywait -e close_write /path/to/file

使用する必要がある場合はlsof(おそらく移植性のために)、次のことを試すことができます。

until err_str=$(lsof /path/to/file 2>&1 >/dev/null); do
  if [ -n "$err_str" ]; then
    # lsof printed an error string, file may or may not be open
    echo "lsof: $err_str" >&2

    # tricky to decide what to do here, you may want to retry a number of times,
    # but for this example just break
    break
  fi

  # lsof returned 1 but didn't print an error string, assume the file is open
  sleep 1
done

if [ -z "$err_str" ]; then
  # file has been closed, move it
  mv /path/to/file /destination/path
fi

修正する

指摘したとおり@JohnWHSSmith以下の最も安全な設計は、常に上記のようにループを使用することですlsof。これは、書き込み用にファイルを開くプロセスが複数ある可能性があるためです。たとえば、読み取り/書き込みフラグを使用してファイルを開く間違って作成されたインデックスデーモンは、実際には読み取り専用です。inotifywaitしかし、まだ睡眠の代わりに使用することができます。睡眠ラインをinotifywait -e close /path/to/file

答え2

代わりに、これは完璧なケースです管路- 2番目のプロセスは、プロセス全体が完了するのを待たず、最初のプロセスの出力が利用可能になるとすぐに処理します。

process1 input_file.dat | process2 > output_file.dat

利点:

  • 一般的にははるかに高速です。
    • ディスクに書き込んで読み込む必要はありません(RAMディスクを使用するとこれを回避できます)。
    • 機械リソースをより完全に活用する必要があります。
  • 完了したら、中間ファイルを削除する必要はありません。
  • OPのように複雑なロックは必要ありません。

パイプラインを直接作成することはできませんが、GNUコアツール以下を使用できます。

tail -F -n +0 input_file.dat | process2 > output_file.dat

入力ファイルを最初から読みます。いくら離れても最初のプロセスはファイルに書き込むことです(まだ起動していないか完了した場合でも同じです)。

関連情報