【sed】treeコマンドが使えない環境でsedコマンドを使うことによりtreeコマンドを作成＆詳細解説[Linux]

#はじめに
`tree`コマンドはディレクトリ構造を確認する際に非常に便利なコマンドですが、macOS（Unix）環境には、`tree`コマンドは対応しておりません。
そこで、[こちら](https://qiita.com/yone098@github/items/bba8a42de6b06e40983b)の記事を参考に、`tree`コマンドを`find`コマンドと`sed`コマンドを組み合わせてほとんど同じような機能を実現するコマンドを作成しました。

同じようなコマンドは、他の記事にも載っていますが、そのコマンドを丁寧に説明した記事がなかったので、自己理解も兼ねて、コマンドを解明しその詳細を記事に書き留めます。

#参考
`sed`コマンドや`正規表現`の理解が曖昧な方は、下記記事が参考になります。

・ [tree コマンドが無い環境で tree コマンドを実現](https://qiita.com/yone098@github/items/bba8a42de6b06e40983b)
・ [sedでこういう時はどう書く?](https://qiita.com/hirohiro77/items/7fe2f68781c41777e507)
・ [sedコマンドの備忘録](https://qiita.com/takech9203/items/b96eff5773ce9d9cc9b3)
・ [サルにもわかる正規表現入門](https://www.mnet.ne.jp/~nakama/)

#（擬似）treeコマンド作成
はじめに、コマンド作成結果と、そのコマンドをエイリアスに設定する手順を示します。

###1. 作成コマンド
```
$ pwd ; find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g' | less
```

###2. エイリアスに設定
```~/.bashrc
alias tree="pwd ; find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g' | less"
```

###3. bashに読み込み
```
$ source ~/.bashrc
```

###4. 確認
```
$ tree
/Users/takuyanin/lang
|--natural
|  |--chinese
|  |--english
|  |--french
|  |--japanese
|  |--russian
|--programming
|  |--compiler
|  |  |--c
|  |  |--c++
|  |  |--fortran
|  |--interpreter
|  |  |--perl
|  |  |--php
|  |  |--python
|  |  |--ruby
|  |--others
|  |  |--java
```
treeコマンドライクに結果が表示されました。Good!

#**詳細解説**
先に示したコマンド`pwd ; find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g' | less`を分割して解説していきます。

ここでは、コマンド実行結果(上記)にも示した、langディレクトリのツリー構造を表示することを目標とするとします。

###1. pwdとfind
```
$ pwd ; find .
```
`;(セミコロン)`について補足します。
`コマンド１ ; コマンド2`とすると、**コマンド１が終了し次第コマンド２を実行します**。ただし、コマンド１の実行結果に関わらずコマンド２実行されることに注意しましょう。

####結果
一番上の`/Users/takuyanin/lang`は`pwd`の実行結果で、
それ以降が`find`の実行結果となります。

```
$ pwd ; find .
/Users/takuyanin/lang
.
./natural
./natural/japanese
./natural/russian
./natural/english
./natural/french
./natural/chinese
./programming
./programming/interpreter
./programming/interpreter/python
./programming/interpreter/perl
./programming/interpreter/php
./programming/interpreter/ruby
./programming/others
./programming/others/java
./programming/compiler
./programming/compiler/c++
./programming/compiler/fortran
./programming/compiler/c
```

###2. pwdとfindとsort
```
$ pwd ; find . | sort
```
`|(パイプ)`について補足します。
`コマンド１ | コマンド2`とすると**コマンド１の結果をコマンド２に渡して実行します**。

####結果
先ほどと違い、結果がソートされているのが確認できます。

```
$ pwd ; find . | sort
/Users/takuyanin/lang
.
./natural
./natural/chinese
./natural/english
./natural/french
./natural/japanese
./natural/russian
./programming
./programming/compiler
./programming/compiler/c
./programming/compiler/c++
./programming/compiler/fortran
./programming/interpreter
./programming/interpreter/perl
./programming/interpreter/php
./programming/interpreter/python
./programming/interpreter/ruby
./programming/others
./programming/others/java
```

###3.1 pwdとfindとsortとsed
```
$ pwd ; find . | sort | sed '1d'
```
`sed '1d'`で1行目を削除します。

####結果
一行目の`.`が削除されているのが確認できます。

```
$ pwd ; find . | LC_ALL=C sort | sed '1d;'
/Users/takuyanin/lang
./natural
./natural/chinese
./natural/english
./natural/french
./natural/japanese
./natural/russian
./programming
./programming/compiler
./programming/compiler/c
./programming/compiler/c++
./programming/compiler/fortran
./programming/interpreter
./programming/interpreter/perl
./programming/interpreter/php
./programming/interpreter/python
./programming/interpreter/ruby
./programming/others
./programming/others/java
```

###3.2 pwdとfindとsortとsed
```
$ pwd ; find . |  sort | sed '1d; s/^\.//'
```
`sed 's/^\.//'`により、先頭のピリオド「`.`」を何も無し「` `」に置換します。
つまり、ピリオド`.`を削除します。


####結果
上記コマンドと実行結果の違いがわかりにくいですが、各行のピリオド`.`が削除されているのが確認できます。

```
$ pwd ; find . |  sort | sed '1d; s/^\.//'
/Users/takuyanin/lang
/natural
/natural/chinese
/natural/english
/natural/french
/natural/japanese
/natural/russian
/programming
/programming/compiler
/programming/compiler/c
/programming/compiler/c++
/programming/compiler/fortran
/programming/interpreter
/programming/interpreter/perl
/programming/interpreter/php
/programming/interpreter/python
/programming/interpreter/ruby
/programming/others
/programming/others/java
```

###3.3 pwdとfindとsortとsed
```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/;'
```
`sed 's/\/\([^/]*\)$/|--\1/;'`について解説します。

・ `[^ ]`： [ ]の中で「^」を記述すると、括弧内の文字以外の任意の一文字を表します。
-> つまり、`[^/]`は「/」以外の任意の一文字

・ ``/\( )\/\1/`` : `\( )\`内の文字を`\1`に代入
-> つまり、`/\/\([^/]*\)$/|--\1/`は、`\/\([^/]*\)$`が仮に`/end`であった時、`\1`は`end`を表すので、`/end`を`|--end`に置換します。
注意点としては、最後尾から一つの`/`のみ対象ということです。
例えば`hoge/fuga/end`は`hoge/fuga|--end`となります。

####結果
下記結果は、上記の説明の通りになっています。

```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/;'
/Users/takuyanin/lang
|--natural
/natural|--chinese
/natural|--english
/natural|--french
/natural|--japanese
/natural|--russian
|--programming
/programming|--compiler
/programming/compiler|--c
/programming/compiler|--c++
/programming/compiler|--fortran
/programming|--interpreter
/programming/interpreter|--perl
/programming/interpreter|--php
/programming/interpreter|--python
/programming/interpreter|--ruby
/programming|--others
/programming/others|--java
```

###3.4 pwdとfindとsortとsed
```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/; s/\/[^/|]*/|  /g'
```
`sed 's/\/[^/|]*/|  /g'`について解説します。
・ `[^/|]` : スラッシュ`/`とパイプ`|`以外の任意の一文字

・ `/\/[^/|]*/|  /g` : `/piyo`といった表示を`|(スペース2つ)`に置換します。
-> つまり`/\/[^/|]*/|  /g`は`/piyo/--aha`を`/ |--aha`に置換します。


####結果
目的どおり結果が表示されました。Great!

```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/; s/\/[^/|]*/|  /g'
/Users/takuyanin/lang
|--natural
|  |--chinese
|  |--english
|  |--french
|  |--japanese
|  |--russian
|--programming
|  |--compiler
|  |  |--c
|  |  |--c++
|  |  |--fortran
|  |--interpreter
|  |  |--perl
|  |  |--php
|  |  |--python
|  |  |--ruby
|  |--others
|  |  |--java
```

###4. pwdとfindとsortとsedとless
最後に、lessコマンドをパイプで繋ぎます。
ツリー構造の表示結果は画面に収まらないことが多々あるので、`less`コマンドを使うことによって、結果をみやすくするとします。

```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/; s/\/[^/|]*/|  /g' | less
```

####結果
今回は、画面に収まる程度ですので、先ほどと実行結果に変化はありませんね。

```
$ pwd ; find . |  sort | sed '1d; s/^\.//; s/\/\([^/]*\)$/|--\1/; s/\/[^/|]*/|  /g' | less
/Users/takuyanin/lang
|--natural
|  |--chinese
|  |--english
|  |--french
|  |--japanese
|  |--russian
|--programming
|  |--compiler
|  |  |--c
|  |  |--c++
|  |  |--fortran
|  |--interpreter
|  |  |--perl
|  |  |--php
|  |  |--python
|  |  |--ruby
|  |--others
|  |  |--java
```

#おわりに
このように、自分の環境にはないコマンドを作成することは、linuxコマンドの勉強にもなれば、作業を効率化するコマンド（シェルスクリプトなど）を独自に作り出せようになりますよね。

この記事が役に立ったという方は、いいね、お願いします(^^)