次のコマンドを検討してください。
find . -type f -name '*.*' -exec mv '{}' '{}_foo' \;
find
この場合、無限ループを防ぐ方法は何ですか?
一方で、私はその発見を知っていますいいえシェルグローブのように動作します。つまり、*.jpg
すべてのファイルのリストを取得するのではなく、内部的にリストを保存して処理します。リスト項目。代わりに、基本オペレーティングシステムはファイルを「増分的に」処理し、各ファイルが認識されるとすぐに処理します(質問に関係がないため、発生する可能性のある特定の量のバッファリングを無視しましょう)。結局のところ、私が知っている限り、これはfind
多くのファイルを含むディレクトリのglobと比較して最大の利点です。
これが真であれば、findがどのように無限ループを防ぐのか理解したいと思います。上記の例では、1.jpg
名前の変更は、1.jpg_foo
StackOverflowと他の場所でのディスカッションで名前を変更すると、ファイル(名前)がディレクトリ内のファイルのリスト内の他の場所を占める可能性があるため、findがファイルに再会できることを知っています。その後、名前を変更します。再び(に1.jpg_foo_foo
)など。
明らかに、このようなことは起こらないでしょう。
ベストアンサー1
単一のディレクトリでは、処理する前にファイルの完全なリストを読むのと同じくらい簡単にできます(そしてstrace
何が起こったのかを示すもの)。
# keep reading entries first
openat(AT_FDCWD, ".", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 4
getdents(4, /* 1024 entries */, 32768) = 32752
getdents(4, /* 1024 entries */, 32768) = 32768
getdents(4, /* 426 entries */, 32768) = 13632
getdents(4, /* 0 entries */, 32768) = 0
close(4) = 0
(読みやすくするために出力を要約)
# process stuff later
clone(...
wait4(...
--- SIGCHLD...
clone(...
wait4(...
--- SIGCHLD ...
しかし、一般的に言えば、find
ループはまったくブロックされません。ファイルをサブディレクトリに移動すると、これが何度も発生します。
mkdir -p sub/sub/sub/sub
find -type f -exec mv {} sub/{}_foo \;
sub/sub/sub/sub/file_foo_foo_foo_foo
これにより、このようなことが発生する可能性があります。 (-depth
この場合は役に立ちます)。
find
存在しない魔法を盲目的に使用するよりも、衝突の可能性を最初から避けることをお勧めします。編集する前に質問したのは、名前が変更されたファイルとまったく一致しないため、良い解決策です。
厳しい要件がない場合でも、ファイルを2回処理することはできず、処理しないことを明確にするのが最善です。ここでは、ファイルのjpg
代わりにファイルの名前を変更しますfoo
。
またfind
、単一の呼び出しでファイルが2回処理されるのを防いでいても、スクリプト全体が再度実行され、findが2回目に実行されるリスクが常にあるため、どちらも適切な保護措置を講じる必要があります。