Bashシェルスクリプトで空ディレクトリを再帰的に検索し削除する
はじめに
開発が進むと、アプリケーション内に不要な空ディレクトリが誕生することがあります。
そのまま残り続けていると、本当に必要なディレクトリなのかわからなくなることがあります。
あるいはサーバのデータディレクトリ、ワークディレクトリも削除処理が実装されていない場合に不要な空ディレクトリが残ってしまう場合があります。
そんなときな空ディレクトリを再帰的に検索して一気に削除してしまいましょう。
シェルで実現するためのかんたんなワンライナーを紹介します。
検証環境
$ uname -moi
x86_64 x86_64 GNU/Linux
$ head -n 2 /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
$ find --version | head -n 2
find (GNU findutils) 4.5.11
Copyright (C) 2012 Free Software Foundation, Inc.
動作確認のための準備
動作確認のために適当なディレクトリツリーを作成しておきます。
# 適当な作業ディレクトリを作成
$ mkdir work/ && cd work/
# ディレクトリとファイルを作成
$ mkdir -p a/d/
$ mkdir -p b/e/
$ mkdir -p b/f/
$ mkdir -p b/g/h/
$ mkdir -p b/g/i/j/
$ mkdir -p "c c/"
$ touch a/d/hoge.txt
$ touch b/f/hoge.txt
tree
コマンドで、作成されたディレクトリツリーを確認してみます。
$ tree
.
|-- a
| `-- d
| `-- hoge.txt
|-- b
| |-- e
| |-- f
| | `-- hoge.txt
| `-- g
| |-- h
| `-- i
| `-- j
`-- c\ c
10 directories, 2 files
上記から分かる通り、以下のディレクトリを空ディレクトリとして削除したいです。
./b/e/
./b/g
./c c/
方法その 1 : find
コマンドと xargs
コマンドを組み合わせる
残念ながら、空ディレクトリの検索は ディレクトリツリーの末端ディレクトリ しか対象になりません。
どういうことかというと ./b/g
ディレクトリ以降は空のディレクトリしかないため、こちらのディレクトリも削除したいのですが、残念ながら検索結果として出力されません 。
末端ディレクトリを削除した後であれば見つかります。
find
コマンドで空のディレクトリを検出し、結果を xargs
コマンドで 1 つずつ削除すればいいわけです。
ちゅうしなければ行けない点は、以下の過去エントリで取り上げています。
- シェルスクリプトで名前にスペース(空白)を含むファイルが xargs でうまく処理できない場合の対処 | ゲンゾウ用ポストイット
- xargs にパイプで渡した標準入力が空だった場合におかしな動きをしないようにする | ゲンゾウ用ポストイット
ポイントは 3 点。
- ディレクトリパスにスペースが含まれていても正しく動作するように、先程の
find
コマンドに-print0
オプションを付与 xargs
コマンドに-0
オプションを付け、find -print0
で渡ってきたディレクトリリストを null 文字で区切るxargs
コマンドに-r
オプションを付け、find
の結果 1 ディレクトリも見つからなかった場合でも正しく動作するようにする
$ find . -type d -empty -print0 | xargs -0 -r -n 1 rmdir
# ディレクトリツリーを表示してみる
$ tree
.
|-- a
| `-- d
| `-- hoge.txt
`-- b
|-- f
| `-- hoge.txt
`-- g
`-- i
6 directories, 2 files
./b/g
ディレクトリは空ですがまだ残っています。
これを削除するためには何度か今回のコマンドを実行してやる必要があります。
# 再度削除
$ find . -type d -empty -print0 | xargs -0 -r -n 1 rmdir
$ tree
.
|-- a
| `-- d
| `-- hoge.txt
`-- b
|-- f
| `-- hoge.txt
`-- g
5 directories, 2 files
# 再々度削除
$ find . -type d -empty -print0 | xargs -0 -r -n 1 rmdir
$ tree
.
|-- a
| `-- d
| `-- hoge.txt
`-- b
`-- f
`-- hoge.txt
4 directories, 2 files
何回繰り返せばよいのかわからないため、繰り返しの終了条件をうまく定義してやる必要がありますね。
方法その 2 : find
コマンドの -delete
オプションを利用する
もう一つの方法として、 find
コマンドの -delete
オプションを利用するというものがあります。
こちらはどういう仕組みなのか、空ディレクトリのみを内包するディレクトリがあった場合にまとめて削除してくれますし、
パスにスペースが含まれていたとしてもあんじょう取り扱ってくれます。
$ find . -type d -empty -delete
$ tree
.
|-- a
| `-- d
| `-- hoge.txt
`-- b
`-- f
`-- hoge.txt
4 directories, 2 files
ちなみに、 -delete
オプションが利用できない find
バージョンも有るようなので注意が必要です。
$ find --version | head -n 2
find (GNU findutils) 4.5.11
Copyright (C) 2012 Free Software Foundation, Inc.
ひとこと
面倒な点もよしなにやってくれるので、 find
コマンド + -delete
オプションの方法を採用するのが容易そうですね。
ディスカッション
コメント一覧
まだ、コメントがありません