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

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

先の2つの記事で、UNIX 端末上で複数のファイルを並べて表示する方法と、ansicolum コマンドについて書いた。今回は、ansicolumn コマンドを改造して、複数ファイルの同時表示対応したという話題。

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

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

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

https://github.com/kaz-utashiro/App-ansiecho

## ファイルを複数指定するだけ

まず、ansicolumn コマンドのインストールについては[こちら](https://github.com/kaz-utashiro/App-ansiecho#install)を参照。と言っても `cpanm App::ansicolumn` するだけ。cpanm (App::cpanminus) のインストールについては、環境によって違うので調べてください。

やり方は簡単。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)

以上...


## --parallel/--no-parallel オプション

...でもなんなので、もう少し説明する。とりあえず、コマンドやオプションをあれこれ組み合わせるのに比べると、非常にシンプルなインタフェースで実現できることはわかっていただけたと思う。

一応、このために `--parallel` というオプションを新設した。ただ、２つ以上のファイルが引数に指定されると自動的に有効になるので、わざわざ指定する必要はない。`--parallel` オプションが指定されると、ボーダー表示 `--border` (`-B`)、行の折り返し `--linestyle=wrap`、画面の幅一杯に表示 `--widen` (`-W`) オプションが有効になる。 そのため、ファイルを複数指定しただけで、上の例のような出力形式になる。デフォルトのボーダースタイルは `box`。

逆に、無効にしたい場合には `--no-parallel` オプションを指定する。`--no-parallel` モードで複数ファイルを処理すると、それぞれのファイルを逐次的に処理する。ただし、横方向のパラメータに関しては、すべてのファイルのデータに基づいて統一的に決定する。一方で、縦方向のパラメータ、たとえばページの高さなどは、それぞれのファイル毎に決定する。各ファイル毎にすべてのパラメータを決めていたのでは、個別にコマンドを実行するのと変わらないからだ。同時表示か否かに関わらず、起動時にすべてのファイルの内容を読み込んで処理するので、多くのファイルを指定する時には注意が必要だ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/9792a2b3-f7b5-d6a4-63ce-4f172c46a35d.png)

上の例では、2つのファイルのすべての行の最大長からカラム数を2に設定し、それはすべてのファイルに対して適用される。

## カラム数指定

次の例は、[week] コマンドを使って12ヶ月分のカレンダーのファイルを用意して ansicolumn で表示している。

![スクリーンショット 2022-10-13 8.35.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/4c8f5404-f211-95ee-56c4-8ae332c008d6.png)

この例だと、5ヶ月以上のデータを表示しようとすると、表示幅が足りなくなってしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/841d6e65-27c4-5908-eb27-6901b62f1954.png)

このような場合は、`-C` オプションでカラム数を指定すれば、その単位で出力することができる。

![スクリーンショット 2022-10-13 8.40.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/693b571b-eab5-0a66-5a59-1391486ccecc.png)

## ドキュメント表示

複数のドキュメントを並べて表示すると、このようになる。`--parallel` オプションではページ制御の機能はすべて無効になるので、それぞれのファイルの内容は最も長いファイルに合わせてすべて連続して出力され、足りない部分は空白で埋められる。この例では、`-p` (`--paragraph`) と `-D` (`--document`) オプションを指定しているので、連続する空白以外の行の間には空行が挿入され、禁則処理が有効になっている。

<!--
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/0f3fa72d-ab42-ff3a-4fb1-beddfdd3f125.png)
-->

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/517f46d1-34aa-c093-800d-93d171f07fb6.png)

## ansicolumn を2段重ねで使う

ややトリッキーだが、ansicolumn を組み合わせて使うこともできる。次の例では、新旧仮名使いの資料をそれぞれ2カラムのページモードで出力した結果を、さらに複数ファイルで並べて表示している。

```
$ ansicolumn <(ansicolumn -w2/3- -pDPC2 sorekara-old.txt) <(ansicolumn -w2/3- -pDPC2 sorekara-new.txt) --border=none
```

![スクリーンショット 2022-10-13 14.37.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/43ccc7a6-e28f-193c-f822-18aec9ba3507.png)

前の記事では説明しなかったが、ansicolumn の幅や高さの指定では、`-w2/3-` のような記法を使うことができる。`-w` は、全体の幅を指定するオプションで、`2/3-` は逆ポーランド記法の式だ。スタックには画面の幅が最初に積まれているので、これは `width / 2 - 3` という意味になる。半分よりやや狭い幅で2カラム出力した結果を並べて表示しているというわけだ。

## diff を見る

上の例は夏目漱石の「それから」の新旧仮名遣いによるものだ。両者を比較したいのであれば、sdif コマンドなどを使うのが便利だ。

![スクリーンショット 2022-10-13 15.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/2c6abb97-e0e4-6eb1-1e32-5963d6b5c233.png)

ただ、これはデータチェックのための体裁であって、文章を読ませようというのとはちょっと違う。少々工夫すると、diff の結果を ansicolumn コマンドで読みやすい形式で出力することができた。

![スクリーンショット 2022-10-13 15.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/6907123a-77c2-53b3-af33-2cf6313ca891.png)

上の例は、sdif がバックエンドで使っている cdif コマンドを2回使っている。cdif の、`--no-old`, `--no-new` オプションを使うと、いずれか一方のファイルの内容だけを表示することができる。

ちなみに、cdif は、文字単位ではなく単語単位で比較する。上の例では、さらに mecab コマンドによる形態素解析の結果に基づいて比較をおこなっている。若干区切りにおかしい点があるのは、旧仮名使いによるものもあるが、そもそも現代語とは少し違うので、うまく対応できていないからだろう。

# 他の ANSI 対応ツール

[ansicolumn] 以外にも、[ansifold], [ansiecho], [ansiexpand] などの ANSI 対応ツールがあるので、よかったら試してみていただきたい。いずれも、UNIX の fold, echo, expand/unexpand 互換の仕様をベースに拡張してある。実は、これらのツールは、ほとんど [Text::ANSI::Fold] という Perl モジュールをベースに作られている。このモジュールは、与えられた文字列を指定された長さで分割するという、極めて単純な機能しか持っていない。