find
コマンドを使って、ディレクトリを再帰的にたどって空のディレクトリをすべて削除する方法です。
要件に応じて次の2つのどちらかでできます。
1つ目の方法(空のディレクトリのみを削除)
$ find TARGET -type d -empty | xargs rm -r
2つ目の方法(削除対象のディレクトリしか含まれていなかったディレクトリも削除)
$ find TARGET -type d -empty -delete
または
$ find TARGET -depth -type d -empty -exec rm -v -r {} \;
説明
以下のようなファイル構成だとします。
$ mkdir -p a/b1
$ mkdir -p a/b1/c1
$ mkdir -p a/b1/c2
$ mkdir -p a/b2/c3
$ touch a/b2/c3/d.txt
a/b1
は空ではありませんがからディレクトリのみであり中にファイルが1つもありません。
a/b1/c1
, a/b1/c2
は空のディレクトリです。
a/b2/c3/d.txt
は空のファイルです。
$ find a
a
a/b1
a/b1/c1
a/b1/c2
a/b2
a/b2/c3
a/b2/c3/d.txt
find
に -empty
という条件を付けると空のディレクトリまたは空のファイルを見つけられます。
$ find a -empty
a/b1/c1
a/b1/c2
a/b2/c3/d.txt
-type d
を条件に追加するとで空のディレクトリのみを見つけられます。
$ find a -type d -empty
a/b1/c1
a/b1/c2
これに xargs rm -r
をパイプでつなげることでこの2つのディレクトリを削除できます。
$ find TARGET -type d -empty | xargs rm -r
残ったファイル構成は以下のようになります。
$ find a
a
a/b1
a/b2
a/b2/c3
a/b2/c3/d.txt
a/b1
はいまや空ディレクトリですが、削除前は中にディレクトリがあったので削除されません。
-exec rm -r {} \;
を find
のアクションとして付けても削除できますが、 find
が空のディレクトリを削除してから、そのディレクトリの中身を再帰的にたどろうとするため、余計なエラーメッセージは出てしまいます。
$ find a -type d -empty -exec rm -r {} \;
find: ‘a/b1/c1’: No such file or directory
find: ‘a/b1/c2’: No such file or directory
a/b1/c1
, a/b1/c2
は削除され、 a/b1
は削除されないのは xargs
の場合と同じです。
-depth
というオプションを付け、 -exec rm
を使うとディレクトリの中を再帰的にたどってからそのディレクトリ自身を処理するため、 a/b1
のような削除対象ディレクトリのみのディレクトリも削除してくれます。エラーメッセージも出ません。
$ find a -depth -type d -empty -exec rm -r {} \;
結果はこのようになります。
$ find a
a
a/b2
a/b2/c3
a/b2/c3/d.txt
ここで、 xargs
や -exec rm
の代わりにを -delete
というアクションにすると -depth
が暗黙のうちに指定されたことになり、同じ結果になります。
$ find a -type d -empty -delete
$ find a
a
a/b2
a/b2/c3
a/b2/c3/d.txt
※ -delete
というアクションはPOSIXの標準には含まれないらしいです。環境によってはできないのかも。
-delete
だとなにが削除されたかわからなくて気持ち悪い、という場合は -exec rm -v
のほうがいいかもしれません。
$ find a -depth -type d -empty -exec rm -v -r {} \;
以上。