ZSHではhelpコマンドが使えない!?ビルトインコマンドのマニュアルを表示する方法

# 概要
zshのビルトインコマンドに関して、詳細情報を知りたいと思い、
helpコマンドを叩いてみるものの、
"**zsh: command not found: help**" が表示されるという事象が発生。

それでは"man"の第１引数にコマンド名を渡して表示されるかというと、
出るものと出ないものがある。

例えば変数を宣言する"declare"コマンドをmanしてみると。

```zsh
% man declare
No manual entry for declare
```

勿論helpを打ってもコマンド自体が認識されていないため通らない。
```zsh
help declare
zsh: command not found: help
```
そもそもdeclare自体が無いのではと疑いたくなりますが、
普通にコマンドは使えます。
```zsh
% declare var="hello"
% echo $var
hello

% where declare
declare: shell reserved word
declare: shell built-in command

```
whereでもしっかり、「ビルトインコマンドです」と返されました。

# TL;DR
先に調査結果を載せておきます。

- zshでは"help"でなく"run-help"を使用する。
- デフォルトでは"run-help"は"man"のエイリアスになっている(エイリアスの解除が必要)
- "autoload -Uz run-help"でコマンドを読み込む。
- "run-help"では環境変数"HELPDIR"にマニュアルファイルのパスを通さないと対象のコマンド名を引数にして検索することができない

# 調査

## zshのビルトインコマンド一覧をみる
こちらの記事からzshのビルトインコマンドの一覧を確認できることを知る。
[ビルトインコマンドの一覧を"見やすく"見る方法](https://qiita.com/DaikiSuyama/items/ff0d23a38b6d050a9fa4)

```zsh
% man zshbuiltins
```
すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3292417/0d7439d9-24cf-2783-6ddb-cf2c72d64ee7.png)
表示されました。

## 2767行の中から探すのは嫌...
先述のコマンドは普通にマニュアル情報も確認できるのですが、
全てのビルトインコマンドの情報が載っているので量は膨大です。
```zsh
% man zshbuiltins | wc -l
    2767
```
2767行...

勿論、検索かけることは可能ですが、
ちょっと面倒くさいですし、それが正攻法とも思えず、
ここら辺の仕様をちょっと調べてみました。
("run-help 対象コマンド"の方式で検索できるようにしたい)

>Bash とは違い、Zsh は組み込みの help コマンドを有効化しておらず、代わりに run-help を提供しています。デフォルトでは、run-help は >man のエイリアスとなっています。コマンドの前に run-help と付けることで実行できますし、または今タイプしたコマンドに対してキーボードショートカッ>ト Alt+h か Esc h を入力することでも実行できます。
>ArchWikiより：https://wiki.archlinux.jp/index.php/Zsh

これは、Linuxディストリビューションのひとつ、
ArchLinuxの説明を抜粋したものです。
ビルトインコマンドは"run-help"で確認できるようですが、
aliasが設定されているため、manコマンドとして機能するようです...
私の環境はMacですが、恐らく同様でしょう。

念の為aliasが設定されているか確認してみました。

```zsh
ll='ls -l'
ls='ls -G'
run-help=man
which-command=whence
```
やはり、エイリアスが設定されてますね。

unaliasで解除したいところですが、
run-helpコマンドの仕様もよくわからないので、
まずはrun-helpがどこに格納されているか確認してみることに。

### run-helpの実行ファイル格納場所

```zsh
% sudo find / -name run-help -type f 
/usr/share/zsh/5.8.1/functions/run-help
%
% ll /usr/share/zsh/5.8.1/functions/run-help
-rwxr-xr-x  1 root  wheel  3198  2  9 18:39 /usr/share/zsh/5.8.1/functions/run-help
```
それっぽいのが引っ掛かりました。

### 中身を見る
```zsh
#!/bin/zsh
#
# Figure out where to get the best help, and get it.
#
# Install this function by placing it in your FPATH and then
# adding to your .zshrc the lines:
#       unalias run-help
#       autoload -Uz run-help
#
※以降スクリプト処理のため省略
```
バイナリではなく、
普通にソースコードが確認できます。

### run-helpを実行してみる。
```zsh
#declareをrun-helpの引数にして実行
% /usr/share/zsh/5.8.1/functions/run-help declare

ZSHMISC(1)                  General Commands Manual                 ZSHMISC(1)

NAME
       zshmisc - everything and then some

SIMPLE COMMANDS & PIPELINES
       A simple command is a sequence of optional parameter assignments
       followed by blank-separated words, with optional redirections
       interspersed.  For a description of assignment, see the beginning of
       zshparam(1).

       The first word is the command to be executed, and the remaining words,
       if any, are arguments to the command.  If a command name is given, the
       parameter assignments modify the environment of the command when it is
       executed.  The value of a simple command is its exit status, or 128
       plus the signal number if terminated by a signal.  For example,

              echo foo

       is a simple command with arguments.

       A pipeline is either a simple command, or a sequence of two or more
       simple commands where each command is separated from the next by `|' or
:
```
"ZSHMISC(1)"なるものが立ち上がりました(最初のドキュメントとは微妙に違う)
MISCは英語の"miscellany(文集)"の略でしょうか？
文集だけあり、量は膨大で、
```zsh
#"-N"で　行数を表示
   2215 
   2216 zsh 5.8.1                      February 12, 2022                    ZSHM   2216 ISC(1)
(END)
```
2216行あります。
(wc -lだと行数が正しく表示されませんでした)

引数にビルトインコマンドを渡しましたが、特にその位置に飛んでくれるようなこともなく、
どのコマンドを渡しても必ずトップページが表示されます。

そもそも、引数はちゃんと受け渡されているのだろうか？
試しに引数なしで打ってみます。

```zsh
% /usr/share/zsh/5.8.1/functions/run-help     
There is no list of special help topics available at this time.

% /usr/share/zsh/5.8.1/functions/run-help hello
hello not found
No manual entry for hello
```
コマンドは通りません。一応ちゃんと引数を見てますね。

ちなみに、後述する方法でパスを通した後に"run-help"引数無しで実行すると、
ビルトインコマンドの一覧が表示されるようになります。

## 手詰まりのためネットで情報を探す
ソースコードが見えるので、run-helpの中身を確認するのも一つの手ですが、
正直面倒くさかった。
ということで、ネット検索。

### しかし情報が全然引っかからない...
zshの情報ってこんな少ないの？ってくらい合致する情報が引っ掛かりません。
マニュアル確認なんて、基礎的な部分だからすぐに解決すると甘く見てました...

### 日本語の情報を諦め、海外の情報を探ってみる。

>This is because the HELPDIR isn't set. You have to find the install location for zsh's help files and >set the env var to that dir. On my system that looks like this:
>引用：https://til.hashrocket.com/posts/cxcby4mz0n-zsh-comes-with-help-set-the-helpdiryo

何やら、"HELPDIR"という環境変数を作って、そこにzshのマニュアルファイルが格納されているディレクトリを設定してあげるといったような内容が記載されております。

参考サイトの場合マニュアルファイルの場所は
```zsh
/usr/share/zsh/help
```
が指定されておりましたが、
私の環境では以下のパスでした。
```zsh
/usr/share/zsh/5.8.1/help

ls /usr/share/zsh/5.8.1/help 
alias         compvalues    getln         rehash        unlimit
autoload      continue      getopts       return        unset
---省略
```
各ビルトインコマンドのマニュアルファイルが格納されております！

ちなみに、5.8.1 はzshのバージョンですね。
```zsh
% zsh --version
zsh --version
zsh 5.8.1 (x86_64-apple-darwin22.0)
```
### 環境変数"HELPDIR"を設定する。

それではこのパスを先ほどの環境変数"HELPDIR"に設定してみます。
```zsh
export HELPDIR='/usr/share/zsh/5.8.1/help'
% env
#---省略
HELPDIR=/usr/share/zsh/5.8.1/help
#---省略
```
それでは第１引数にビルトインコマンドを指定して実行してみる。
```zsh
/usr/share/zsh/5.8.1/functions/run-help declare

typeset [ {+|-}AHUaghlmrtux ] [ {+|-}EFLRZip [ n ] ]
        [ + ] [ name[=value] ... ]
typeset -T [ {+|-}Uglrux ] [ {+|-}LRZp [ n ] ]
        [ + | SCALAR[=value] array[=(value ...)] [ sep ] ]
typeset -f [ {+|-}TUkmtuz ] [ + ] [ name ... ]
       Set or display attributes and values for shell parameters.
#---省略
```
一見間違ったコマンドが引っかかっているように見えるかもしれませんが、
declareコマンドはtypesetのマニュアルへシンボリックリンクされているため正しい動作です。
```zsh
% ls -l /usr/share/zsh/5.8.1/help | grep declare
lrwxr-xr-x  1 root  wheel      7  2  9 18:39 declare -> typeset
```
これで引数を指定して対象のビルトインコマンドのページを確認することができるようになりました！

### run-helpで実行できるようにする
個人的にはもう満足なのですが、
一応"run-help"のpathを通してコマンド名だけで使用できるようにしてみましょう。

```zsh
% /usr/share/zsh/5.8.1/functions:ki$ alias
#---省略
run-help=man
#---省略

% unalias run-help
% autoload -Uz run-help
% run-help pwd
pwd [ -rLP ]
       Print  the  absolute  pathname of the current working directory.
       If the -r or the -P flag is specified, or the CHASE_LINKS option
       is  set  and the -L flag is not given, the printed path will not
       contain symbolic links.
```
これで"run-help"が期待通り動くようになりました！
当初の想定よりも大分苦戦しました。

## 環境
OS:macOS Ventura 13.2.1
zsh:5.8.1

## 参考
https://wiki.archlinux.jp/index.php/Zsh

https://til.hashrocket.com/posts/cxcby4mz0n-zsh-comes-with-help-set-the-helpdir