ターミナルで複数のファイルを並べて表示する方法（改造編）

[week]: https://github.com/kaz-utashiro/App-week
[ansicolumn]: https://github.com/tecolicom/App-ansicolumn
[ansifold]: https://github.com/tecolicom/App-ansifold
[ansiecho]: https://github.com/tecolicom/App-ansiecho
[ansiexpand]: https://github.com/tecolicom/App-ansiexpand
[greple]: https://github.com/kaz-utashiro/greple
[optex]: https://github.com/kaz-utashiro/optex
[Text::ANSI::Fold]: https://github.com/tecolicom/Text-ANSI-Fold

以前、UNIX 端末上で複数のファイルを並べて表示する方法と、ansicolum コマンドを使って実現する方法について書いた。

https://qiita.com/kaz-utashiro/items/345cd9abcd8e1f0d81a2

https://qiita.com/kaz-utashiro/items/1cdd71d44eb11f3fb36e

https://qiita.com/kaz-utashiro/items/32e1c2d4c42a80c42422

# ansicolumn でファイルを並べて表示する

https://github.com/tecolicom/App-ansicolumn

結論は簡単で、`ansicolumn` コマンドに複数のファイルを与えて実行すればいいだけだった。

![スクリーンショット 2022-10-12 20.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/8b041a16-9c3e-629d-0bf0-ece578ef19a7.png)

# 3つのデータを同時に見たい

ファイルを並べてみたいことは結構あって、そんな時に便利に使っていた。ターミナルの幅が狭くて表示できない場合には、画面を広げるとか、フォントを小さくするとかで対応することができる。

最近になって、ある2つのファイルを並べて表示したくなった。1つのファイルに用語のリストが含まれていて、もう1つのファイルには、同じ行に含まれる用語の日本語訳と、その読みがタブで区切られて書かれている。この3つのデータを同時に並べてみたいというのは自然な発想だろう。

まあ、`ansicolumn` を使って2つのファイルを並べて表示することはできるのだが、最初のファイルには1つの項目、2番目のファイルには2つの項目が含まれているので、1番目と2番目の項目の間に隙間がありすぎてスカスカするし、離れているので対応が取りにくいのだ。

## paste でつなげる

まず考えられるのは、2つのファイルを組み合わせて1つのデータにする方法だ。これは、最初の記事で紹介した `paste` コマンドを使えばいい。

```sh
paste terms.txt japanese.txt | column -t
```

のようにすれば、3つの項目を整列して表示することができる。

ここで問題なのは、それぞれのデータの中には空白文字が含まれていることと、タブは1つではなく、桁合わせのために複数入っていることだ。タブが1つに限られていれば `column` コマンドの `-s` オプションでタブを指定すればいい。roff の tbl 形式はそのようなものだが、決して見やすい形式ではない。

## ansicolumn -r オプション

こういう時のために、今年の夏に `ansicolumn` コマンドに `-r` オプションを追加してあった。普通は `-s` オプションには分割に使う文字を列挙するのだが、`-r` オプションと一緒に使うと `-s` の値を正規表現として解釈するようになる。

```sh
paste terms.txt japanese.txt | ansicolumn -rs '\t+'
```

こうすると、タブ文字の連続を区切りとして要素を整列することができる。

ちなみに、今回のケースであれば、`sed` で複数のタブを1つに変換すれば `column` コマンドで処理することもできる。もっと複雑なパターンを指定したい場合や、分割文字を出力に含めたい場合には `-r` オプションが不可欠となる。

## ansicolumn -X (--cell) オプション

これがすべてのファイルに通用するわけではないので、`ansicolumn` コマンドに新しいオプションを追加して、それぞれのファイルの表示幅を指定できるようにした。`ansicolumn` には、元々カラムの幅を指定するための `--pane-width` (`-S`) というオプションがある。しかし、`column` コマンドは同一種類のデータをマルチカラムで表示するためのものなので、処理の都合上、この幅を可変にするのは難しい。GNU の `ls` などはそんな処理をしているようだが、恐ろしくてソースを見たくない。おそらく、バックトラックのようなアルゴリズムを実装する必要がある。

### 絶対値指定

難しい原因は、横方向のパラメータが変化すると縦方向の処理に影響が出るからだ。そして、縦方向のパラメータが変化すると、また横方向の処理に影響が出るのだ。しかし、複数ファイルを表示するパラレルモードでは、縦方向の変化は発生しない。というわけで、パラレルモードだけで有効になる `-X` (`--cell`) というオプションを追加した。

```sh
ansicolumn terms.txt japanese.txt -X 40,120
```

のように使うと `term.txt` を40カラム、`japanese.txt` を120カラムで表示する。

### 相対指定

表示幅を相対的に指定することもできる。デフォルトでは、2つのファイルであれば、それぞれ画面の半分の幅で表示する。もしそれが80カラムだとしたら、次のようにすると、上の例と同じ結果になる。

```sh
ansicolumn term.txt japanese.txt -X-40,+40
```

### 最長行指定

それぞれのファイルに含まれる最長行を基準にすることもできる。

```sh
ansicolumn term.txt japanese.txt -X=
```

のように `-X` オプションの値として `=` を指定する。

`=` の値には最大値を指定することができて、

```sh
ansicolumn term.txt japanese.txt -X=40,=120
```

のようにすると、それぞれのファイルの最長のデータが40カラムと120カラムを超えければその長さ、それより長かったら40と120に設定される。

たとえば、

```sh
ansicolumn -X=,=80,=80 /etc/{paths,passwd,services}
```

を実行するとこうなる。

![スクリーンショット 2023-11-26 19.07.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/34cda4f4-bfa5-c727-6a7e-b8af9e7b2f6e.png)

`/etc/passwd` と `/etc/services` は80カラムを超えるので、それぞれ80カラムで折り返されている。

## TODO

`ansicolumn` の他のパラメータは逆ポーランド記法で式が書けるようになっているが、`-X` オプションはそうなっていない。そうすれば、比率を指定して画面を分割するような使い方が可能になる。しかし、元々、他にやりたい作業があってそのために実装したので、これにあまりかまけていると、本来の作業が一向に進まない。そのうち、気が向いたら実装するかもしれない。