あなたの知らない less の世界

最近 [prezto][] 入れたんですよ。prezto。そしたらいつものシェル世界が見違えるほど使いやすくなって身長も 3 メートルくらい伸びたんですが、それは余談でして、prezto 入れた後に less 使ってみたら余りの変わりっぷりに驚いたんです。

これを機に man page を読み直してみたら更に驚き。less ってこんなスゴイ物だったのか！みたいな。今回はそんな less の底力を紹介します。

[prezto]: https://github.com/sorin-ionescu/prezto

# 環境変数 `$LESS`

less には様々なオプションがあるのですが、これを予め環境変数 `$LESS` に設定しておくと、毎度 `less ファイル名` と打つだけでそれが有効になります。更に、後述しますが、この設定は less 起動中にオン・オフして切り替えることが可能です。

```sh
# 最低限でもこれくらいは設定しておこう
export LESS='-i -M -R'

# 僕は後述の物を全部付けてます（-L 以外）
export LESS='-g -i -M -R -S -W -z-4 -x4'
```

| オプション | 意味                                                                                         |
|:----------:|----------------------------------------------------------------------------------------------|
|    `-g`    | 検索したとき、ヒットした全ての文字列を反転するのではなく、現在カーソルがある行のみ反転する。 |
|    `-i`    | 検索時に全部小文字で入力したときだけ、大文字小文字を無視する。                               |
|    `-M`    | 詳しいプロンプトを表示する。                                                                 |
|    `-R`    | ANSI カラーエスケープシーケンスを解するようになる。                                          |
|    `-S`    | 一行が長く、ターミナルの幅が狭くて表示できない場合、途中までしか表示しない。                 |
|    `-W`    | 一度に2行以上移動した場合、新たに表示した最初の行をハイライトする。                          |
|   `-z-4`   | ウィンドウのサイズをターミナルのサイズ - 4 に設定する。                                      |
|    `-x4`   | タブを 4 つのスペースで表現する。                                                            |
|    `-L`    | `$LESSOPEN` 環境変数を無効にする。                                                           |

## `-g`, `--hilite-search` オプション

これは画像を見た方が早いでしょう。通常 less で検索した場合、画面全てでヒットした文字列がハイライトされますが、`-g` を付けるとカーソルがある行に限定されます。

<img width="634" alt="スクリーンショット_2016-08-06_15_58_17.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/535ae1db-0acf-e007-7210-8bb4db2de299.png">

`/検索語句` で検索した後、<kbd>N</kbd> or <kbd>Shift</kbd> + <kbd>N</kbd> でポンポン移動してるときは、カーソル行以外で強調表示する意味がないのでこの設定を付けています。

## `-i`, `--ignore-case` オプション

`/kensaku` は `kensaku`, `KenSaku`, `KENSAKU` 全てにヒットしますが、`/Kensaku` は `Kensaku` にのみにヒットするようになります。Vim でいう `set smartcase` ですね。

## `-M`, `--LONG-PROMPT` オプション

これも画像の通り。通常の less は `:` だけの味気ないプロンプトですが、`-M` を付けると `lines 531-586/1406 43%` みたいに`行数/総行数 割合`を表示します。

* 通常表示  
  <img width="354" alt="スクリーンショット 2016-08-06 16.06.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/20592d7a-d05d-ba91-c14d-c688e5ec4ed9.png">
* `-M` オプション付き  
  <img width="354" alt="スクリーンショット 2016-08-06 16.06.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/fd44c61d-25b4-a617-2a02-b17122f9a845.png">

ただし、`総行数` と `割合` はファイルを最終行まで読み込んだ時だけ表示されます。

## `-R`, `--RAW-CONTROL-CHARS` オプション

これは多くの人が既に利用しているでしょう。効果も画像を見れば説明不要ですね。

```sh
curl 'https://api.github.com/repos/git/git/commits' | jq . -C | less
```

* `-R` オプション無し  
  <img width="434" alt="スクリーンショット 2016-08-06 16.12.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/9b731ad7-b0dd-d549-fd31-d64c7f32b446.png">
* `-R` オプション有り  
  <img width="434" alt="スクリーンショット 2016-08-06 16.12.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/8ce6b2ff-29f8-62d0-b9c2-edf7c4821559.png">

## `-S`, `--chop-long-lines` オプション

一行の長さが画面幅を超える場合でも改行しません。一行がひたすら長いけど、一番左が見えれば十分、みたいなファイルに最適です。Web サーバーのログとかにいいですね。Vim で言うなら `set nowrap` みたいな機能です。

* `-S` オプション無し  
  <img width="434" alt="スクリーンショット 2016-08-06 16.15.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/bee53b4d-e4c0-08b0-067c-52811636c726.png">
* `-S` オプション有り  
  <img width="434" alt="スクリーンショット 2016-08-06 16.16.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/2b9eea5c-bc05-9071-8edc-8a2891baad6d.png">

## `-W`, `--HILITE-UNREAD` オプション

less では <kbd>Control</kbd> + <kbd>D / U</kbd> や <kbd>Control</kbd> + <kbd>F / B</kbd> でそれぞれ 1/2 画面分、1 画面分の移動が出来ますが、突然切り替わるとどこまで自分が読んでいたのか分からなくなります。それが、`-W` を付けると今まで表示されていた部分の **1 行下**を反転することで知らせてくれます。

イマイチ伝わりにくい機能ですね……。実際に試した方が分かりやすいかも。

## `-[z]n`, `--window=n` オプション

ウィンドウの大きさを決めるオプションです。ウィンドウというのは一画面の行数を表します。つまり、<kbd>Control</kbd> + <kbd>F</kbd> で動く行数ですね。`-z10`、あるいは、`-10` とだけ指定すると、一度の <kbd>Control</kbd> + <kbd>F</kbd> で 10 行進むようになります。

これには負数も指定できて、僕の例のように `-z-4` とすると、ターミナルの幅より 4 行少ない行数が選択されます（less 起動中にターミナルの行数を変えると自動的に認識してくれます）。

Vim で言うなら `set scrolloff` ですね。

## `-xn,...`, `--tabs=n,...` オプション

タブ（`\t`）を空白で表すときの文字数を指定します。Vim で言うなら `set tabstop` なんですが、ちょっと違うところは幅を不定に出来るところです。`-x2,3,5,7,11,13,17` みたいにすると素数幅でインデントされます。見にくいだけですが。

ただし、このオプション、**環境変数 `$LESS` に何らかのオプションがあると効きません**（El Capitan 附属の less 458 で確認）。バグだよなこれ……。

## `-L`, `--no-lessopen` オプション

これは僕も `$LESS` に加えていません。`$LESSOPEN` 機能を無効にするものです。後で詳述します。

# オプションを動的に変更する

## 起動前に変更する

環境変数 `$LESS` の値は less の起動時に付けたオプションで上書きされます。たとえば

```sh
# 画面幅を超えた部分はちょん切る
export LESS=-S
```

のように設定している場合、

```sh
# -S の反対は -+S
less -+S /var/log/access.log
```

`+` を付けて一時的に無効に出来ます。

## 起動後に変更する

`-S` を ON にして起動した後、「ｼﾏｯﾀ！折り返して表示しないとダメなログだった！」と気付いて less を再起動してませんか？ その必要はありません！ オプションは起動中に On/Off 出来るんです。たとえば `-S` オプションなら

* <kbd>-</kbd> <kbd>S</kbd> で On / Off をトグル。
* <kbd>-</kbd> <kbd>+</kbd> <kbd>S</kbd> で On。

に出来ます（切り替わらない場合は <kbd>J / K</kbd> などで画面を再描画してください）。

* 正確に言うと、<kbd>-</kbd> <kbd>+</kbd> は「On にする」という意味ではありません。ここについては[コメントを受けて追記][]欄に詳しく載せています。

[コメントを受けて追記]: http://qiita.com/delphinus/items/b04752bb5b64e6cc4ea9#コメントを受けて追記20161123

## <kbd>Control</kbd> + <kbd>D / U</kbd> の飛び幅を変更する

<kbd>Control</kbd> + <kbd>D</kbd> で下方向、<kbd>Control</kbd> + <kbd>U</kbd> で上方向に画面半分だけ移動できるのですが、流し読みしてるときにこれでは早すぎることがあります。かといって <kbd>J / K</kbd> では遅すぎるし……という方に朗報。<kbd>Control</kbd> + <kbd>D / U</kbd> の前に数値を指定すると、以後その行数だけ移動するようになります。

たとえば、<kbd>3</kbd> <kbd>Control</kbd> + <kbd>D</kbd> と押すと、以後 <kbd>Control</kbd> + <kbd>D / U</kbd> で 3 行毎に移動するようになります。`less` を起動し直すと又元に戻ります。

`$LESS` にこれ設定したいんですけど、それは無理みたい……。

* と思ってたらこれできました！後述の[コメントを受けて追記][]を参照してください。

# 検索にヒットした行だけを表示する

これは超便利！ 長大なログから知りたい行だけを探すとき、

```sh
grep 192.168.0.20 /var/log/hoge.log | less
```

なんてしてませんか？ こんな用途なら less 単体で十分です。起動中に <kbd>&amp;</kbd> `検索語句` <kbd>Enter</kbd> と打つと`検索語句`を含む行だけを表示します。`検索語句` には正規表現も使えます。

又、`grep -v` のような、**検索にヒットしない行だけ**を表示することも可能です。この場合は <kbd>&amp;</kbd> <kbd>!</kbd> `検索語句` <kbd>Enter</kbd> としてください。

ただこの機能も万能ではありません。非常に大きなログでこれをやると、しばらく固まったままうんともすんとも言わないことがありました。大きなログに対しては `grep` とか `tail` とかを個別に利用した方がいいと思います。

# `tail` の代わりとして利用する

`less` 起動中に <kbd>Shift</kbd> + <kbd>F</kbd> を押すと、ファイルに追記される度に画面上でも追随して行を追加してくれます。Syslog や Web サーバーのログなどを監視するときに便利です。キャンセルするときは <kbd>Control</kbd> + <kbd>C</kbd> で OK です。

特に便利なのは、<kbd>&amp;</kbd> で絞り込んだ後の <kbd>Shift</kbd> + <kbd>F</kbd> で、特定の行だけを監視できることです。デバッグ中に <kbd>&amp;</kbd> <kbd>!</kbd> `DEBUG` <kbd>Enter</kbd> などとして、デバッグメッセージ**以外だけ**を監視したり出来ます。

ただこの機能もべらぼうに大きいログだと重くなりがちなので、その時は、`watch -n1 'tail | grep'` とかで代用しましょう。

# man を色つきで見る

## 環境変数 `$PAGER`

これは既に多くの方が設定していると思います。

```sh
export PAGER=less
```

このように設定すると `man` などの様々なコマンドがページャーとして `less` を使うようになります。この場合、`man` 使って居るときも先述の `$LESS` が有効です。

## 環境変数 `$LESS_TERMCAP_*`

`$PAGER` を設定した状態で以下の環境変数を指定すると man ページに色が付きます。

```sh
export LESS_TERMCAP_mb=$'\E[01;31m'      # Begins blinking.
export LESS_TERMCAP_md=$'\E[01;31m'      # Begins bold.
export LESS_TERMCAP_me=$'\E[0m'          # Ends mode.
export LESS_TERMCAP_se=$'\E[0m'          # Ends standout-mode.
export LESS_TERMCAP_so=$'\E[00;47;30m'   # Begins standout-mode.
export LESS_TERMCAP_ue=$'\E[0m'          # Ends underline.
export LESS_TERMCAP_us=$'\E[01;32m'      # Begins underline.
```

* before  
  <img width="754" alt="スクリーンショット 2016-08-07 8.03.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/861c7b1c-5bc6-0fb5-99bb-109e17c7bafd.png">
* after  
  <img width="754" alt="スクリーンショット 2016-08-07 8.03.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/48ee783d-a392-eec2-ddd4-a620feec4505.png">

まあ色がついたからと言って、ものすごい見やすいわけでもないんですが、下線や点滅表示に対応していないターミナルで、好きな色を使えるのは良いでしょう。

# LESSOPEN でシンタックスハイライト

環境変数 `$LESSOPEN` を指定すると、`less` で表示する前に、内容を別のツールで整形することが出来ます。この機能に対応したいろいろなツールが既にあるのですが、オススメは [wofr06/lesspipe][lesspipe] です。Homebrew なら `brew install lesspipe` でインストールできます。

[lesspipe]: https://github.com/wofr06/lesspipe

これをインストールした上で、`.bashrc` などで以下のように設定します。

```sh
if which lesspipe.sh > /dev/null; then
  export LESSOPEN='| /usr/bin/env lesspipe.sh %s 2>&-'
fi
```

これで OK。後は普通に `less hoge.rb` などとすると、Ruby 用のシンタックスハイライトが自動で適用されます。

* before  
  <img width="722" alt="スクリーンショット 2016-08-07 8.30.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/cd6086c7-8265-a3fb-c7c0-33afcab4aa39.png">
* after  
  <img width="722" alt="スクリーンショット 2016-08-07 8.30.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/8880/31100783-2829-8134-f89a-db807ce91e98.png">

邪魔なときは `less hoge.rb:` のように、最後に `:` を付ければ無効に出来ますし、`less hoge.rb:perl` みたいに、無理矢理別の種別を適用することも出来ます。

便利な機能なのですが、困ったことに <kbd>Shift</kbd> + <kbd>F</kbd>（`tail` の代わりとして利用する）との併用が出来ません。こういうときのために `-L` オプション（`$LESSOPEN` を無視する）がありますので利用しましょう。

----

あれもこれもと書いていたらずいぶん長くなってしまいました。全ての環境で全ての機能が使えるとは限りませんが（特に `lesspipe` とか）、知ってればどこかで役に立つと思いますよ！

----

# コメントを受けて追記（2016/11/23）

## 起動中にオプションを切り替える方法

改めて man ページを読んでみますと、これには様々な方法がありました。ちょっと覚えるのが大変なくらい……。画面幅で表示をちょん切る `-S` オプションを例にして説明します。

| キーマップ                             | 意味                                                                     |
|----------------------------------------|--------------------------------------------------------------------------|
| <kbd>-</kbd> <kbd>S</kbd>              | オプションを ON/OFF で切り替える。                                       |
| <kbd>-</kbd> <kbd>+</kbd> <kbd>S</kbd> | オプションをデフォルトにリセットする（つまり、画面幅で折り返す）。 |
| <kbd>-</kbd> <kbd>!</kbd> <kbd>S</kbd> | オプションをデフォルトの反対にする（つまり、画面幅でちょん切る）。       |

* それぞれのキーマップで、<kbd>S</kbd> の直前に <kbd>Control</kbd> + <kbd>P</kbd> を入れると変更後の設定を画面下に表示しません。
* それぞれ、<kbd>-</kbd> ではなく <kbd>-</kbd> <kbd>-</kbd> を使うと、長いオプションが使えます。
  - （例）`--+chop-long-lines` などとすると、起動オプションがどうであれ、必ず画面幅でちょん切ります。こんな長いキーマップ打ってられない！と思われるかもしれませんが、実際にはコマンド補完が効くので、<kbd>-</kbd> <kbd>-</kbd> <kbd>+</kbd> <kbd>c</kbd> <kbd>h</kbd> `ここでコマンドが自動補完` <kbd>⏎</kbd> で入力できました。

## 起動時にコマンドを予め入力する方法

起動時に `+` に続けて打った文字列は、ファイルを開いたときに入力されます。……これじゃ訳分かりませんね。つまり以下のようにしてファイルを開くと、

```sh
less +F /var/log/system.log
```

起動後に <kbd>Shift</kbd> + <kbd>F</kbd> を押したときのように、自動的に“tail -f モード”でファイルが開くわけです。これを利用するといろいろなことができます。

```sh
less +G /var/log/system.log
```

最初から最終行を表示したり、

```sh
less +'&network^M' /var/log/system.log
```

ネットワークに関わるログだけを表示します（こんな用途なら grep 使え、という話ではありますが）。このとき `^M` はそのまま入力してはダメです。<kbd>Control</kbd> + <kbd>V</kbd> <kbd>⏎</kbd> のようにして、改行せずに Enter キーをそのまま入力します。

* <kbd>Control</kbd> + <kbd>V</kbd> は **verbatim insert** とか **quoted insert** とか呼ばれる bash / zsh の機能です。

更にこれは、`$LESS` にも設定可能です。ずっと↑の方で

> たとえば、<kbd>3</kbd> <kbd>Control</kbd> + <kbd>D</kbd> と押すと、以後 <kbd>Control</kbd> + <kbd>D / U</kbd> で 3 行毎に移動するようになります。`less` を起動し直すと又元に戻ります。
> 
> `$LESS` にこれ設定したいんですけど、それは無理みたい……。

なんて書いてたんですが、

```sh
export LESS='+3^D^U'
```

このように設定することで可能になりました！（例によって、`^D`, `^U` は <kbd>Control</kbd> + <kbd>V</kbd> に続けて入力してください。）

## 複数ファイルを開く &amp; 編集する

これはコメントで指摘されて気付いたのですが、less は複数ファイルを指定しての起動もサポートしています。起動中には以下のようなコマンドが使えます。

| キーマップ                | 意味                   |
|---------------------------|------------------------|
| <kbd>:</kbd> <kbd>N</kbd> | 次のファイルへ。       |
| <kbd>:</kbd> <kbd>P</kbd> | 前のファイルへ。       |
| <kbd>:</kbd> <kbd>X</kbd> | 最初のファイルに戻る。 |

又、`-M` オプションを指定してる場合、ファイルの最後までスクロールすると次のファイルのファイル名が表示されます。

```sh
cd /usr/local/Homebrew/Library/Homebrew
less *rb
```

この例ではあんまり意味がありませんが、以下のように使うと便利です。

1. `find ... | xargs less` で見つけたファイルを全部 less で開く。
2. 上記のキーマップでファイルを行き来して目当てのファイルが見つかったら <kbd>V</kbd>。
  - <kbd>V</kbd> を押すと予め `$EDITOR` に設定しておいたエディターでファイルが開きます。
3. エディターを終了すると less に戻ってくるので 1. の繰り返し。

----

追記の割にはかなり長くなってしまいましたが、man ページを読むとまだまだここに載せていない機能がたくさんありました。いつも何気なく使っているコマンドでも、man ページを読み直すといろいろ発見があって楽しいですね。