shell

less にパイプしても色が消えないようにする方法

More than 3 years have passed since last update.


はじめに

Linux のコンソールで動くいまどきのユーティリティは、出力に色が付いていて見やすくなっているものが多いです。例えば ls コマンドや git diff など、色があるだけで視認性が大幅に向上するツールは色付きで使いたいですよね。ところが、こういった色付きの出力を行うツールはたいてい less と相性が悪い。

$ ls -al | less

のように出力をパイプに流した途端に色が付かなくなってしまいます。建前としては、出力がコンソールのときには最終的に出力を人間が見るので色を付けても構わないが、出力がパイプの時には下流のツールが正しくエスケープシーケンスを処理できるとは限らないので、色付けを無くしてエスケープシーケンスを出力することに起因する問題を未然に防ごう、ということです。

でも、less の場合には -R オプション付ければ色付けのエスケープシーケンスは正しく扱えるんですよね。だから、パイプの向こう側が less のときにはエスケープシーケンスもちゃんと出して欲しい。でも、プログラム側(例えば /bin/ls)から見て出力のパイプが -R 付きの less かどうかなんて判定するのはちょっと難しい。だから、GNU ls なんかだと色を付けるかどうかを手動で指定するオプションとかがあって、それを使うと less に色付きの出力を渡すことができます。

$ ls -al --color=always | less -R

でも、この方法は ls 以外で通用するとは限らないので ls 以外で色を付けたくなったら毎回 man を開いてオプション名を確認しなくてはならず面倒ですし、そもそもそういったオプションが用意されていないツール相手には無力です。


汎用的な方法

expect というソフトウェアパッケージに unbuffer というツールが含まれていて、unbuffer を経由してプロセスを起動すると、標準入出力があたかもコンソールであるかのように偽装することができます。インストール方法は yum でも apt でもなんでも入るので割愛して、使い方から解説します。ls だったらこんな感じです。

$ unbuffer ls -al | less -R

git でも同じように使えます。

$ unbuffer git diff | less -R

ツールによっては存在しない --color オプションとは違って、この方法ならツール側の対応無しで出力に色を付けたまま less に渡すことができます。とっても便利。


シェルの設定

unbuffer と less の組み合わせは毎回手でタイプしてももちろん良いのですが、面倒なので .bash_profile などにエイリアスを登録して楽をしています。

less_with_unbuffer () {

unbuffer "$@" |& less -SR
}
alias ul=less_with_unbuffer

このように設定しておいて、使うときには ul を頭に付けるだけ。

$ ul ls -al

とか、

$ ul git diff

とか、そんな感じです。本当は、

$ unbuffer git diff | grep --after=3 'Foo::' | less -SR

こんな感じで色々パイプを繋いで最後に less -SR するパターンをエイリアスで

綺麗に書けると良いのですが、私の shell 力だとすぐにはやり方を思いつかない。