ディレクトリ・ファイルの構成を確認したいとき、treeコマンドをよく使う。
$ tree . ├── fuga │ └── index.html └── hoge ├── fuga │ └── piyo │ └── index.html ├── index.html └── text.txt 4 directories, 4 files
ただ、たまにtreeコマンドが使えない&treeコマンドをインストールできない環境を利用することがある。
そのような環境でディレクトリ・ファイル構成を知りたいときに使えるスクリプトを考えてみようと思った。
当然、このような発想を実現した先駆者は既に存在しており、「treeコマンド 再現」とかで調べれば答えを知ることができる。
ただ、今回は勉強も兼ねて自分でゼロから考えてみたいと思ったので、そのようなネタバレ?はあえて調べずに検討してみた。
なので当然自分の再現結果は最適化されたものではない可能性が高く、実際に利用するときは他のつよつよエンジニアの方が考案された擬似treeコマンドを利用する方がいいと思う。
先に結論を書いておく。
$ find . | sed 's/[^\/]*\//\//g; s/^\/\([^\/]*\)$/├── \1/g; s/\/\([^\/]*\)$/└── \1/g; s/\// /g; s/^ /│ /g' . ├── hoge │ └── index.html │ └── fuga │ └── piyo │ └── index.html │ └── text.txt ├── fuga │ └── index.html
このコマンドを細かく分解していく。
配下のファイル一覧をfindコマンドで出力するとこんな感じになる。
$ find . . ./hoge ./hoge/index.html ./hoge/fuga ./hoge/fuga/piyo ./hoge/fuga/piyo/index.html ./hoge/text.txt ./fuga ./fuga/index.html
この状態からsed
を駆使していい感じにtree
っぽくしていく。
見た感じ<ディレクトリ名/
を空白
に置き換えればいい感じに階層になりそう。
% find . | sed 's/[^/]*\// /g' . hoge index.html fuga piyo index.html text.txt fuga index.html
もうこれでいい気がしてきた。
まあ、そういうわけにもいかないのでもう少し考えてみる。
まず、最下層以外のファイル名はツリー構造に影響を与えないのでカットする。
$ find . | sed 's/[^\/]*\//\//g' . /hoge //fuga ///piyo ////index.html /fuga //index.html
最上層のファイル名を├── ファイル名
にする。
$ find . | sed 's/[^\/]*\//\//g; s/^\/\([^\/]*\)$/├── \1/g' . ├── hoge //index.html //fuga ///piyo ////index.html //text.txt ├── fuga //index.html
最下層のファイル名を└── ファイル名
にする。
% find . | sed 's/[^\/]*\//\//g; s/^\/\([^\/]*\)$/├── \1/g; s/\/\([^\/]*\)$/└── \1/g' . ├── hoge /└── index.html /└── fuga //└── piyo ///└── index.html /└── text.txt ├── fuga /└── index.html
階層を表現するため、/
を空白3つに変換する。
$ find . | gsed 's/[^\/]*\//\//g; s/^\/\([^\/]*\)$/├── \1/g; s/\/\([^\/]*\)$/└── \1/g; s/\// /g' . ├── hoge └── index.html └── fuga └── piyo └── index.html └── text.txt ├── fuga └── index.html
最後に先頭を│
でつなげる(先頭の空白を│
に置き換える)。
$ find . | gsed 's/[^\/]*\//\//g; s/^\/\([^\/]*\)$/├── \1/g; s/\/\([^\/]*\)$/└── \1/g; s/\// /g; s/^ /│ /g' . ├── hoge │ └── index.html │ └── fuga │ └── piyo │ └── index.html │ └── text.txt ├── fuga │ └── index.html
ドンッ!!
悪くない気がする。
find
とsed
コマンドだけでここまで綺麗に表現できるとは思わなかった。
第2階層以下で│
を表示できないのが気になるが、│
を表示するかどうかは直後の行に依存するので今回は諦めた(find
の表示順番を考慮実現できるかもしれない)。
実際はtree
コマンドを使える機会が多いのでこれを利用する頻度はそんなにないと思うけど、思ったより簡単なsed
で再現できた。
どうでもいいが、sed
の置換処理はエスケープがあると何やってるかわかりづらいから人に説明するときはエスケープを除いたコマンドを見せる方が良さそうだなと思った(コピペされないように注意する必要もありそうだけど)。