manをもっと便利に使おう!(ビルトインコマンドに対応 + 色付きで表示)


はじめに

よく使うコマンドの筆頭にmanコマンドがありますが(僕調べ)、builtinコマンドや、"if"などの予約語についても同じように調べたいことがあるかと思います。

また、manページをlessで表示するときに、デフォルトでは白黒となっていますが、より見やすくするために色付きで表示するようにします。

使用するシェルはzshで、それ以外のシェルでは動作しません

ビルトインコマンド、エイリアス、予約語に対する扱い

$ whence -wa cd

を実行すると、

cd: alias
cd: builtin

のように、cdがシェルにどのように解釈されるかを表示することができます。

(上の例のように複数の対象が存在する場合にはfzfなどで選択すればよいでしょう。)

": "の右側には"builtin","reserved","alias","function","command","hash","none"がくるので、この値に応じて異なる動作をするように新たにmanコマンドを定義し直すことにします。

参考になるもの:

ただし、上の場合にはbashのビルトインコマンドに関しての話なので、今回はzsh用にしてみたいと思います。

for builtin commands

man zshbuiltinsを実行し、そのあと/cdのように実行されるようにします。

$ man_indent=7
$ _space="$(printf '%*s' "${man_indent}" '')"
$ /usr/bin/man --pager="less -p'^${_space}cd '" zshbuiltins

(TODO: コマンドの字下げ幅は環境依存でないか?)

注意

Ubuntuなどでzshbuiltinsがない場合には、手動でインストールする必要があります(バージョンに注意)。

$ mkdir -p ~/Downloads/zsh-doc; cd $_
$ wget http://downloads.sourceforge.net/project/zsh/zsh/5.0.2/zsh-5.0.2.tar.bz2
$ tar -xvf zsh-5.0.2.tar.bz2
$ sudo cp Doc/*.1 /usr/local/share/man/man1

man cd

結果:

for reserved words

man zshallの"COMPLEX COMMANDS"と"ALTERNATE FORMS FOR COMPLEX COMMANDS"のセクションに、具体的な使い方が書かれているので、

$ /usr/bin/man --pager="less -p'^COMPLEX COMMANDS$'" zshall

が実行されるようにします。

(builtinの時と同じようにしてもよかったのですが、esacなどがマッチしないので。)

man esac

結果:

for aliases

whenceコマンドのcshフォーマットでの出力をみるようにします。

$ whence -c dot
dot: aliased to dot_main

(dot_mainは関数)

結果:

for functions

whence -f dot_mainとすれば、その関数dot_mainの中身を表示します。
pygmentizeコマンドなどが使えれば、カラーでハイライトして表示できるので、それを使い$MANPAGERで表示します。
(後述するようにless -Rを指定していればカラー表示出来るようになります。)

if hash pygmentize 2>/dev/null; then
  whence -f "$1" \
    | pygmentize -l sh \
    | ${MANPAGER:-${PAGER:-less}}
else
  whence -f "$1" | ${MANPAGER:-${PAGER:-less}}
fi

man man

結果:

その他の場合

通常のman hogeが実行されるようにします。

以上をまとめると

man.zsh
# vim: set ft=zsh
#=#=#=
# man (available for buitlin commands)
#
# **Features:**
#
# * for zsh builtin commands
# * for reserved word
# * for alias
# * for zsh function
# * for (natural) command
# * if the same name exists, choose one by fzf
# * with color
#
# >* [Can I get individual man pages for the bash builtin commands? - Unix & Linux Stack Exchange](http://unix.stackexchange.com/questions/18087/can-i-get-individual-man-pages-for-the-bash-builtin-commands)
# >* [manpage - How to make `man` work for shell builtin commands and keywords? - Ask Ubuntu](http://askubuntu.com/questions/439410/how-to-make-man-work-for-shell-builtin-commands-and-keywords)
#
# But I want to know about zsh builtins, so I wrote this.
#
# Install zsh manuals to enable `man zshbuiltins`:
#
# ```
# $ mkdir -p ~/Downloads/zsh-doc; cd $_
# $ wget http://downloads.sourceforge.net/project/zsh/zsh/5.0.2/zsh-5.0.2.tar.bz2
# $ tar -xvf zsh-5.0.2.tar.bz2
# $ sudo cp zsh-5.0.2/Doc/*.1 /usr/local/share/man/man1
# ```
#
# **Require:**
#
# * fzf
# * "pygmentize" or "highlight" for highlighting scripts
# * LESS="R" option for ansi color in "less" command
#=#=

function man() {
  # Stock current LANG
  _LANG=${LANG}

  # set language (but if MANLANG is already set, use that)
  export LANG=${MANLANG:-${_LANG}}

  function restore_lang() {
    # restore LANG and clean up name space
    export LANG=${_LANG}
    unset _LANG
    unset -f $0
  }

  trap restore_lang 1 2 3 EXIT

  if [ ! -n "$1" ]; then
    echo "What manual page do you want?"
    return 1
  fi

  # get man type (using fzf but you can replace it with peco or percol or zaw)
  word="$(whence -wa -- $1 | uniq | fzf -1 | sed 's/: / /' | cut -d' ' -f2)"

  # if escaped, do nothing
  if [ ! -n "${word}" ]; then
    return 0
  fi

  # switch operation by word
  case ${word} in
    builtin) # built-in command
      local man_indent _space
      # TODO: get how many spaces before the commands
      man_indent=7
      _space="$(printf '%*s' "$man_indent" '')"
      /usr/bin/man --pager="less -p'^${_space}\\$1 '" zshbuiltins
      ;;
    reserved) # reserved words
      /usr/bin/man --pager="less -p'^COMPLEX COMMANDS$'" zshall
      ;;
    alias) # alias
      whence -c $1
      ;;
    function) # function
      if hash pygmentize 2>/dev/null; then
        whence -f "$1" \
          | pygmentize -l sh
      elif hash highlight 2>/dev/null; then
        whence -f "$1" \
          | highlight --out-format=ansi --src-lang=Bash
      else
        whence -f "$1"
      fi
      ;;
    *) # try using man
      /usr/bin/man "$@"
      ;;
  esac
}

manページを色付きで表示する

上にあげた画像を見てもらえれば分かるように、色付きでmanページが見られるといろいろと捗ります。

参考:

~/.zshrc

export PAGER=less

としておけば、manコマンド実行時にはlessコマンドを使って表示します。

lessコマンドのオプションは環境変数LESSに指定することができるので(See man less)、

export LESS='-iMRj.5'

と指定しておきます。

オプション 意味
-i ignore-case
-M long-prompt
-R ANSIカラー表示
-j.5 ターゲット行を画面の中心に

また参考リンクのように~/.zshrcに以下のように書いておけば、太字や下線、ハイライト時の色を指定することができます。

export LESS_TERMCAP_mb=$(tput bold)                # begin blinking
export LESS_TERMCAP_md=$(tput bold; tput setaf 4)  # begin bold (blue)
export LESS_TERMCAP_me=$(tput sgr0)                # end mode
export LESS_TERMCAP_se=$(tput sgr0)                # end standout-mode
export LESS_TERMCAP_so=$(tput bold; tput setaf 3)  # begin standout-mode (yellow)
export LESS_TERMCAP_ue=$(tput rmul; tput sgr0)     # end underline
export LESS_TERMCAP_us=$(tput smul; tput setaf 2)  # begin underline (green)

僕はtputを使って色などを指定していますが、エスケープ文字を使って直接指定することもできるので、細かく調節したい人はこちらを使うといいと思います。

まとめると:

終わりに

manコマンドを活用するために、ビルトインコマンド等も同じmanで参照できるようにしました。また、色付きで表示されると見やすくなると思いますので、色付き表示の仕方もご紹介しました。
何かしら役に立てば幸いです。