lsof
から マニュアルページ
コマンド名、ファイル名、インターネットアドレスまたはファイル、ログイン名、NFS ファイル、PID、PGID、またはリストするように要求された UID を見つけられなかったなどのエラーが検出された場合、Lsof は 1 を返します。 -V オプションが指定されている場合、lsof はリストに失敗した検索項目を示します。
つまり、あなたの lsof failed for some other reason
句は決して実行されません。
外部プロセスがまだ開いている間にファイルを移動しようとしましたか?宛先ディレクトリが同じファイルシステム上にある場合、基になる i ノードが同じままであるため、3 番目のプロセスから元のパスでアクセスする必要がない限り、それを行うことに問題はありません。そうでなければ 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
更新
以下の @JohnWHSmith が指摘したように、最も安全な設計では常に lsof
を使用します。 複数のプロセスがファイルを書き込み用に開いている可能性があるため、上記のようにループします (実際には読み取り専用にする必要があるファイルを読み取り/書き込みフラグで開く、不適切に作成されたインデックス作成デーモンが例として挙げられます)。 inotifywait
ただし、sleep の代わりに使用することはできますが、sleep 行を inotifywait -e close /path/to/file
に置き換えるだけです。 .
別のアプローチとして、これは パイプstrong> の完璧なケースです - 2 番目のプロセスは、プロセス全体が終了するのを待つのではなく、最初のプロセスからの出力が利用可能になるとすぐに処理します:
process1 input_file.dat | process2 > output_file.dat
利点:
- 全般的に高速:
- ディスクへの書き込みと読み取りを行う必要はありません (これは、RAM ディスクを使用すると回避できます)。
- マシン リソースをより完全に使用する必要があります。
- 終了後に削除する中間ファイルはありません。
- OP のように複雑なロックは必要ありません。
パイプを直接作成する方法がないが、GNU coreutils がある場合 これを使用できます:
tail -F -n +0 input_file.dat | process2 > output_file.dat
これにより、入力ファイルの最初からの読み取りが開始されます。 どこまで 最初のプロセスはファイルの書き込みです (まだ開始されていない、または既に終了している場合でも)。