サブツリー内のすべての空のディレクトリを削除する方法は?


151

サブツリー内のすべての空のディレクトリを削除するにはどうすればよいですか?私は次のようなものを使用しました

find . -type d -exec rmdir {} 2>/dev/null \;

しかし、空のディレクトリのみを含むディレクトリを削除するには、複数回実行する必要があります。さらに、特にcygwinの場合は非常に遅くなります。


emacsソリューションについては、emacs.stackexchange.com / q / 12190/2264も参照してください。
ショーンオールレッド

回答:


222

GNU findオプションと述語を組み合わせて、このコマンドは仕事をするべきです:

find . -type d -empty -delete
  • -type d ディレクトリに制限する
  • -empty 空のものに制限する
  • -delete 各ディレクトリを削除します

-depthによって暗示されているように指定する必要なしに、木は葉から歩きます-delete


2
-deleteすでに暗示されている-depthので、手動で指定する必要はありません。
jamadagni 14

1
おかげで、私はそれに気づかなかった。回答が更新されました。
クリストフドレヴェドロゲ14

11
-mindepth 1空の場合は、開始ディレクトリ自体が削除されないように、ここに追加します。
グレッグドゥビッキー

2
偉大な、しかし...私の古いSunOSのホスト上で動作しません
dokaspar

2
!シェルにとって特別な意味を持ちます。あなたはそれをエスケープする必要があります。次のようなもの:\! -name 'Completed'直前に-delete動作するはずです。または、このディレクトリにマーカーファイルを置くだけです。
クリストフドレヴェドロゲ

53

深くネストされたディレクトリを最初にリストします。

find . -depth -type d -exec rmdir {} \; 2>/dev/null

(リダイレクトが適用されることに注意してくださいfindだけでなくに、全体としてコマンドrmdirだけのためにリダイレクト。rmdirあなたは、中間シェルを起動する必要があるだろうとして、重要な景気減速を引き起こします。)

findに述語をrmdir渡すことで、空でないディレクトリでの実行を回避でき-emptyます。GNU findは、コマンドを実行しようとするときにディレクトリをテストするため、空になったばかりのディレクトリが選択されます。

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

スピードアップする別の方法は、rmdir呼び出しをグループ化することです。どちらも、特にCygwinのもとでは、オリジナルよりも著しく高速である可能性があります。これら2つの間に大きな違いはないと思います。

find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null

より速い方法は、空でないディレクトリの数によって異なります。-empty呼び出しをグループ化するためのメソッドと組み合わせることはできません。空のディレクトリのみを含むディレクトリはfind、それらを見るまでに空ではないためです。

別の方法は、複数のパスを実行することです。これが高速かどうかは、find実行間でディレクトリ階層全体がディスクキャッシュに残ることができるかどうかなど、多くの事項に依存します。

while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done

または、zshを使用します。グロブ修飾子は Fそう、非空のディレクトリにマッチする/^F空のディレクトリにマッチします。空のディレクトリのみを含むディレクトリは、それほど簡単には一致しません。

while rmdir **/*(/N^F); do :; done

(これrmdirは、空のコマンドラインを受け取ると終了します。)


それでおしまい。90秒の代わりに0.90秒かかります。
-maaartinus

@maaartinus:私は好奇心が強いです:なしで試すことができる同様のデータセットがあります-pか?私はそれが違いを生むとは思わなかったでしょう。
ジル

3
@maartinus —その他の小さな最適化:これを追加すること-emptyで機能するはずです(ただし、どれだけの利益が得られるかはわかりません)。そして、あなたはおそらく削除したくないので、非常に些細なことですが.、を使用してください-mindepth 1
mattdm

これは削除ではなく、プロセスがオーバーヘッドで起動するため、ほぼすべての時間がかかりました。私は-depth議論を見落としていましたrmdir -p。私はすでにコメントを変更しました。90秒は私の最初の試みでした。ここでは驚くべきことは何もありません。
maaartinus

2
私たちは削除することができます実現rmdir:このコマンドを使用して、少なくともGNUで見つけ、完全にコマンド呼び出しをfind . -depth -type d -empty -delete
クリストフDrevet-Droguet

6

あなただけのタック場合は-p、あなたにrmdir、それは1回のパスで動作します。それはきれいでも最適でもありませんが、すべてを手に入れるべきです。これは、削除するディレクトリの空でない親ディレクトリを削除するようrmdirに指示します。

-emptyfindにテストを追加することで少し節約できるので、空でないディレクトリに悩まされません。


3

find . -depth -type d -exec rmdir {} +

この質問に対する最も簡単で標準に準拠した回答です。

残念ながら、ここで示されている他の回答はすべて、すべてのシステムに存在しないベンダー固有の拡張機能に依存しています。


3
この回答では、削除できないディレクトリごとに、望ましくない可能性があるエラーが発生します。
ウィレム・ファン・ケチッチ

0

find . -type d -printf "%d %p\n" |\ sort -nr |\ perl -pe 's/^\d+\s//;' |\ while read dir; do \ (rmdir "$dir" > /dev/null 2>&1); \ done

仕組みは次のとおりです。

  1. すべてのディレクトリとその深さを再帰的にリストする
  2. 深さの降順で並べ替え
  3. ディレクトリパスのみを除外する
  4. rmdirリストを1つずつ実行します

0

これらのエイリアスは頻繁に使用されるfindコマンドに使用します。特にdupeguruを使用してディスクスペースをクリーンアップする場合は、重複を削除すると多くの空のディレクトリが作成される可能性があります。

内部のコメントな.bashrcので、後で調整する必要があるときに忘れないようにします。

# find empty directories
alias find-empty='find . -type d -empty'

# fine empty/zero sized files
alias find-zero='find . -type f -empty'

# delete all empty directories!
alias find-empty-delete='find-empty -delete'

# delete empty directories when `-delete` option is not available.
# output null character (instead of newline) as separator. used together
# with `xargs -0`, will handle filenames with spaces and special chars.
alias find-empty-delete2='find-empty -print0 | xargs -0 rmdir -p'

# alternative version using `-exec` with `+`, similar to xargs.
# {}: path of current file
# +: {} is replaced with as many pathnames as possible for each invocation.
alias find-empty-delete3='find-empty -exec rmdir -p {} +'

# for removing zero sized files, we can't de-dupe them automatically
# since they are technically all the same, so they are typically left
# beind. this removes them if needed.
alias  find-zero-delete='find-zero -delete'
alias find-zero-delete2='find-zero -print0 | xargs -0 rm'
alias find-zero-delete3='find-zero -exec rm {} +'

-2

rm -r */コマンドは私のために簡単に働きました。ファイルを含むディレクトリを強制的に削除するrm必要があり-fます。rm -r空のディレクトリのみを削除する必要があります。なぜこれが間違っているのか、私は喜んでいます。また*/、フォルダのみを見るため、ファイルを残す必要があります。


1
rm主にファイルを削除することを目的としているため、最初に徹底的にテストすることを強くお勧めします。一方で*/ディレクトリのみにマッチし、私はそれがより深いレベルで何をするかわかりません。また、一部のシステムでのみ機能することも想像できます。
maaartinus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.