`find -type d -exec rmdir {} \;` コマンドが「そのようなファイルまたはディレクトリはありません」というメッセージを生成するのはなぜですか?

`find -type d -exec rmdir {} \;` コマンドが「そのようなファイルまたはディレクトリはありません」というメッセージを生成するのはなぜですか?

テスト目的で、次のディレクトリを作成しました。

user@linux:~$ mkdir dir0{1..3}

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir03
user@linux:~$ 

そして、私はそれを取り除いたfind -exec

user@linux:~$ find -type d -exec rmdir {} \;
rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory
find: ‘./dir01’: No such file or directory
find: ‘./dir03’: No such file or directory
user@linux:~$ 

ディレクトリが削除されたことを確認しました。

user@linux:~$ ls -l
total 0
user@linux:~$ 

私の質問は次のとおりです:

1) なぜメッセージがそこにあったのか分かりません。 理由が分かりますか?

rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory

このようなエラーは見られませんrmdir

user@linux:~$ mkdir dir0{1..3}
user@linux:~$ 

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir03
user@linux:~$ 

user@linux:~$ rmdir *
user@linux:~$ 

user@linux:~$ ls -l
total 0
user@linux:~$ 

2) これらのメッセージを削除することは可能ですか?

答え1

「そのようなファイルまたはディレクトリはありません」というエラーは、削除したばかりのディレクトリに入ろうとしたfindためにfind発生します。デフォルトでは、サブディレクトリに進む前に、現在アクセスしているディレクトリ内のすべての一致する項目にアクションが適用されます。

-depthの呼び出しに追加すると、検索パスの深さ優先検索findが実行findされます。つまり、rmdirディレクトリに対して を実行すると、既にそのディレクトリにアクセス済みであり、再度アクセスしようとしないことになります。

このため、-depthを使用する場合は オプションが暗黙的に指定されます(を持つの実装の場合)。-deletefind-delete

find . -depth -type d -exec rmdir {} \;

-depthユーティリティの標準オプションですfind

空のディレクトリでのみ機能することに注意してくださいrmdir。空でないディレクトリが多数ある場合、上記のコマンドは多数のエラー メッセージを生成します。

代わりに、findサポートされている場合は以下を使用します-empty:

find . -type d -empty -delete

これにより、空のディレクトリが削除されます。

find非標準の-deleteも も持たないの場合-emtpy:

find . -depth -type d -exec sh -c '
    for dirpath do
        set -- "$dirpath"/*
        [ ! -e "$1" ] && rmdir "$dirpath"
    done' sh {} +

これにより、見つかったディレクトリが空であるかどうかがテストされ、空である場合は削除されます。

これは、ディレクトリが空でないことが原因で発生するエラーメッセージを回避するための長いコードですが、生成されたエラーはおそらく「権限が拒否されました」というエラーなので、見るのがもっと面白くなるでしょう。エラーを先頭の/dev/null最初のfindコマンドにリダイレクトすると、このようなエラーは非表示になります。

答え2

おそらく、この-exec ... \;構造により、find は段階的に作業を実行します。

  • ディレクトリツリーをたどって、一致するエントリを探し-type d
  • rmdirそのようなエントリが見つかったらすぐに実行します。

つまり、あなたの例では、 find は を見てdir01、それを後から入るディレクトリとして記憶し、rmdirそれに対して を実行し、その後 に再帰的に移動しようとするとdir01、 が存在しなくなるため失敗します。

この場合、を実行すると-exec rmdir {} +役立つはずです。 への単一の呼び出しrmdir dir01 dir02 dir03が発行されます。これにより、最後の 3 つのエラー メッセージが削除されます。

に関するエラー メッセージは..現在のディレクトリが確かにディレクトリであるものの、rmdir空ではないため削除できないディレクトリであるためです。 を使用して-min-depth検討を中止し、次のコマンドを実行します。

find -mindepth 1 -type d -exec rmdir {} +

これは完璧ではありません。ネストされたディレクトリや一致するディレクトリの数が多いと、エラー メッセージが印刷される可能性がありますが、質問の単純なケースではこれで機能するはずです。

関連情報