treeコマンド、皆さん知ってますか?
そうです、あのファイルやらディレクトリやらを良い感じに木構造で出力してくれるニクい奴です。
こんな感じ
さて、そんなtreeコマンドには多くのオプションがあります。
よく使われるのは -L
だったり、 -a
とかですかね?
そんな中、 -R
オプションというものが存在するのをご存知でしょうか?
Rオプションとは何なのか?
まずは、 --help
オプションに書かれている内容を見てみましょう。
-R Rerun tree when max dir level reached.
直訳すると 最大ディレクトリレベルに達したらツリーを再実行します。
ってとこですかね。
あー、再帰的にツリーを辿るのねと試しに以下のようなコマンドを実行してみました。
$ tree -L 1 -R -o result
これで1階層ごとにtreeの結果が出力されるじゃね?と思ってみました。(あまりやっても意味ないですが・・・
で、やってみた結果、ワーキングディレクトリの下にしかresultが吐かれませんでした・・・
さてはて、予想が外れたのですが冷静に次はmanコマンドを参照してみます。
-R Recursively cross down the tree each level directories (see -L option), and at each of them execute tree again adding `-o 00Tree.html' as a new option.
これを直訳すると
再帰的に各レベルのディレクトリにツリーをたどります(-Lを参照) そして、それらのそれぞれで、新しいオプションとして '-o 00Tree.html'を追加して、それぞれtreeを実行します。
オッ、 --help
の時と違って新たな -o 00Tree.html
という概念が出てきましたね。
ただ、先の実行結果を見渡してみても 00Tree.html
とやらが吐き出されている様子は無い模様。
ますます頭にはてなマークが生えてきました。
treeコマンドのソースコードを読む
このままでは埒が明かないので、treeコマンドのソースコードを読んじゃいましょう。
C言語で書かれているので、そこまで難しくはないはずです。
ソースコードは以下のリンク先からよしなに取得してきてください。
The Tree Command for Linux Homepage
さて、それでは読んでいきたいと思います。
まず、何はともあれ -R
オプションを追っかけましょう。
case 'R': Rflag = TRUE; break;
-R
オプションはこのようにコード内では Rflag
という変数に置き換えられます。
これを追いかけようと、tree.cの中を見てみたのですが、まさかの以下のコードしか参照しているところがありませんでした。
if (Rflag && (Level == -1)) Rflag = FALSE;
んん?意味自体は分かりますが、これが再帰処理に繋がる気配は無さそうですね・・・
一応他のコードも読んでみたのですが、これまたまさかの html.c
というファイル内に以下の意味ありげなコードが書かれていました。
/* This is really hackish and should be done over. */ if (Rflag && (lev == Level) && (*dir)->isdir) { if (nolinks) fprintf(outfile,"%s",(*dir)->name); else { fprintf(outfile,"<a href=\"%s",host); url_encode(outfile,d+1); putc('/',outfile); url_encode(outfile,(*dir)->name); fprintf(outfile,"/00Tree.html\">"); html_encode(outfile,(*dir)->name); fprintf(outfile,"</a><br>\n"); } hdir = gnu_getcwd(); if (sizeof(char) * (strlen(hdir)+strlen(d)+strlen((*dir)->name)+2) > pathsize) path = xrealloc(path, pathsize = sizeof(char) * (strlen(hdir)+strlen(d)+strlen((*dir)->name) + 1024)); sprintf(path,"%s%s/%s",hdir,d+1,(*dir)->name); fprintf(stderr,"Entering directory %s\n",path); hcmd = xmalloc(sizeof(char) * (49 + strlen(host) + strlen(d) + strlen((*dir)->name)) + 10 + (2*strlen(path))); sprintf(hcmd,"tree -n -H \"%s%s/%s\" -L %d -R -o \"%s/00Tree.html\" \"%s\"\n", host,d+1,(*dir)->name,Level+1,path,path); system(hcmd); free(hdir); free(hcmd); }
うーーーーーん、This is really hackish and should be done over.というコメントから察するに、なんか難易度高そうっすね・・・
一応この処理は -H
オプションを付けて実行した際のHTMLを構築する処理の一部になります。
HTML構築のためにディレクトリを -L
で指定した深さまで辿っている途中に、この処理が出てくるのですが、ざっくり読み解いてみると、どうやらRオプションがあり、かつLオプションで指定した深さのディレクトリの場合にHTMLを出力しつつ、再帰的に tree
コマンドを実行していますね。
manの説明にあった、 00Tree.html
の存在も伺えます。どうやら再帰的に実行する際に、各ディレクトリに 00Tree.html
を生成しているようです。
というわけで、なんとなく分かったこととして -R
オプションは -H
オプションと共に使わないと意味が無さそうってことですね。
では実験してみましょう。
実験
それでは -H
オプションを付加してやってみましょう。
$ tree -L 1 -HR . <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="Author" content="Made by 'tree'"> <meta name="GENERATOR" content="$Version: $ tree v1.8.0 (c) 1996 - 2018 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro $"> <title>Directory Tree</title> <style type="text/css"> <!-- BODY { font-family : ariel, monospace, sans-serif; } P { font-weight: normal; font-family : ariel, monospace, sans-serif; color: black; background-color: transparent;} B { font-weight: normal; color: black; background-color: transparent;} A:visited { font-weight : normal; text-decoration : none; background-color : transparent; margin : 0px 0px 0px 0px; padding : 0px 0px 0px 0px; display: inline; } A:link { font-weight : normal; text-decoration : none; margin : 0px 0px 0px 0px; padding : 0px 0px 0px 0px; display: inline; } A:hover { color : #000000; font-weight : normal; text-decoration : underline; background-color : yellow; margin : 0px 0px 0px 0px; padding : 0px 0px 0px 0px; display: inline; } A:active { color : #000000; font-weight: normal; background-color : transparent; margin : 0px 0px 0px 0px; padding : 0px 0px 0px 0px; display: inline; } .VERSION { font-size: small; font-family : arial, sans-serif; } .NORM { color: black; background-color: transparent;} .FIFO { color: purple; background-color: transparent;} .CHAR { color: yellow; background-color: transparent;} .DIR { color: blue; background-color: transparent;} .BLOCK { color: yellow; background-color: transparent;} .LINK { color: aqua; background-color: transparent;} .SOCK { color: fuchsia;background-color: transparent;} .EXEC { color: green; background-color: transparent;} --> </style> </head> <body> <h1>Directory Tree</h1><p> <a href=".">.</a><br> ├── <a href="./LICENSE">LICENSE</a><br> ├── <a href="./Makefile">Makefile</a><br> ├── <a href="./README.md">README.md</a><br> ├── <a href="./cmd/00Tree.html">cmd</a><br> Entering directory /Users/syossan27/go/src/go-tree/cmd Entering directory /Users/syossan27/go/src/go-tree/cmd/go-tree <br> ├── <a href="./dist/00Tree.html">dist</a><br> Entering directory /Users/syossan27/go/src/go-tree/dist <br> ├── <a href="./go.mod">go.mod</a><br> ├── <a href="./go.sum">go.sum</a><br> ├── <a href="./tree.go">tree.go</a><br> ├── <a href="./tree.html">tree.html</a><br> ├── <a href="./tree_windows.go">tree_windows.go</a><br> └── <a href="./validate.go">validate.go</a><br> <br><br> </p> <p> 2 directories, 9 files <br><br> </p> <hr> <p class="VERSION"> tree v1.8.0 © 1996 - 2018 by Steve Baker and Thomas Moore <br> HTML output hacked and copyleft © 1998 by Francesc Rocher <br> JSON output hacked and copyleft © 2014 by Florian Sesser <br> Charsets / OS/2 support © 2001 by Kyosuke Tokoro </p> </body> </html>
おー、HTMLは無事出力されましたね。
この状態で、 00Tree.html
とやらは各ディレクトリに出力されているのか確認します。
$ tree . ├── LICENSE ├── Makefile ├── README.md ├── cmd │ ├── 00Tree.html │ └── go-tree │ ├── 00Tree.html │ └── main.go ├── dist │ ├── 00Tree.html │ ├── go_tree_darwin_386 │ ├── go_tree_darwin_amd64 │ ├── go_tree_freebsd_386 │ ├── go_tree_freebsd_amd64 │ ├── go_tree_freebsd_arm │ ├── go_tree_linux_386 │ ├── go_tree_linux_amd64 │ ├── go_tree_linux_arm │ ├── go_tree_netbsd_386 │ ├── go_tree_netbsd_amd64 │ ├── go_tree_netbsd_arm │ ├── go_tree_openbsd_386 │ ├── go_tree_openbsd_amd64 │ ├── go_tree_windows_386.exe │ └── go_tree_windows_amd64.exe ├── go.mod ├── go.sum ├── tree.go ├── tree.html ├── tree_windows.go └── validate.go
オッ、たしかに出てますね。
で、出力されたHTMLを見てみると以下のような感じになります。
ほほー?一応cmdディレクトリのリンクを踏んでみましょうか。
なるほど、リンク先もtree構造のHTMLになってますね。
これが -R
オプション無しだと、リンク先を踏んだ場合にはこんな感じになります。
普通にブラウザでローカルディレクトリを覗いた時の画面ですね。
という形の結果になりました。
まとめ
結局のところ -R
オプションってなんぞ?というところなのですが、これはtreeコマンドの開発者が単に内部的に00Tree.htmlを吐く機構が欲しかったから作ったのでは・・・?という感想があります。
CHANGELOGとかも遡って見たり、インターネット上を彷徨ったりしたのですが特に有力な情報は見つからず・・・
あと、ちょっと気になるところとして 00Tree.html
の親ディレクトリへのリンク先を押しても戻ることが出来ず、リンク先の出力ロジックがなんか間違えてるんじゃないかと。
こういった時のバグの報告とかどうやればいいのかちょっと謎なので、treeコマンドに詳しい方、情報お待ちしております。