lessでzipファイルの中身が見えるわけ 〜LESSOPENとlesspipe.sh〜
前回、zipファイルを展開せず中身を見るにはlessコマンドを使うのがよいという記事を書いたが、そもそもなぜlessでzipファイルの中が見れるのか調べてみた。
※前回記事: Linuxでzipファイルの中身を展開せずに見るにはlessがおすすめ - カタカタブログ
lessコマンドの仕組み
どうやら、LESSOPENという環境変数にlesspipe.shというシェルスクリプトが定義されており、これがless実行対象のファイルに対して事前に処理が入る。
$ env | grep LESS LESSOPEN=||/usr/bin/lesspipe.sh %s
つまり、targetというファイルに対してlessコマンドを打つ場合、
$ less target
以下のような処理が内部で行われているようなイメージ。
$ lesspipe.sh target | less
そして、lesspipe.shの中では引数で渡されたファイルの拡張子をチェックし、拡張子ごとにテキスト表示しやすい形式に変換する処理をかませている。例えば、zipやjarの場合は内部でzipinfoコマンドを発行しており、その結果をlessに渡していてくれている。前回の記事ではzipとjarは見れるがwarやearは見れないと書いたが、それはこれが原因だった。
lesspipe.shのzipの部分一部抜粋
case "$1" in (・・・略) *.zip|*.jar|*.nbm) zipinfo -- "$1" ;;
例えば、zipの場合、
$ less target.zip
というコマンドは、
$ zipinfo target.zip | less
のような動きとなり、zipの中身をlessで見れるという仕組みになっている。
ちなみに、当環境のlesspipe.shのロジックは以下のようになっており、zip以外にも様々な形式に対応しているよう。
lesspipe.shの一部抜粋
case "$1" in *.[1-9n].bz2|*.[1-9]x.bz2|*.man.bz2|*.[1-9n].[gx]z|*.[1-9]x.[gx]z|*.man.[gx]z|*.[1-9n]. lzma|*.[1-9]x.lzma|*.man.lzma) case "$1" in *.gz) DECOMPRESSOR="gzip -dc" ;; *.bz2) DECOMPRESSOR="bzip2 -dc" ;; *.xz|*.lzma) DECOMPRESSOR="xz -dc" ;; esac if [ -n "$DECOMPRESSOR" ] && $DECOMPRESSOR -- "$1" | file - | grep -q troff; then $DECOMPRESSOR -- "$1" | groff -Tascii -mandoc - exit $? fi ;;& *.[1-9n]|*.[1-9]x|*.man) if file "$1" | grep -q troff; then man -l "$1" | cat -s exit $? fi ;;& *.tar) tar tvvf "$1" ;; *.tgz|*.tar.gz|*.tar.[zZ]) tar tzvvf "$1" ;; *.tar.xz) tar Jtvvf "$1" ;; *.xz|*.lzma) xz -dc -- "$1" ;; *.tar.bz2|*.tbz2) bzip2 -dc -- "$1" | tar tvvf - ;; *.[zZ]|*.gz) gzip -dc -- "$1" ;; *.bz2) bzip2 -dc -- "$1" ;; *.zip|*.jar|*.nbm) zipinfo -- "$1" ;; *.rpm) rpm -qpivl --changelog -- "$1" ;; *.cpi|*.cpio) cpio -itv < "$1" ;; *.gpg) gpg -d "$1" ;; *.gif|*.jpeg|*.jpg|*.pcd|*.png|*.tga|*.tiff|*.tif)
lesspipe.shの検証
ところで、環境変数LESSOPENの設定やlesspipe.shの実装は環境によって異なるようだが、これはつまりlesspipe.shの実装を好きにカスタマイズできるということだろうか。ということで、今回はCent OS 7.0で簡単な独自lesspipe.shを読ませてlessコマンドの処理が変わるか試してみた。
まずOSとlessのバージョンを示しておく。
$ cat /etc/redhat-release CentOS Linux release 7.0.1406 (Core) $ less --version less 458 (POSIX regular expressions) Copyright (C) 1984-2012 Mark Nudelman less comes with NO WARRANTY, to the extent permitted by law. For information about the terms of redistribution, see the file named README in the less distribution. Homepage: http://www.greenwoodsoftware.com/less
さて、当環境ではデフォルトの状態で環境変数LESSOPENにはlesspipe.shが入っている。%sの部分に対象のファイルが置換されるよう。
$ env | grep LESS LESSOPEN=||/usr/bin/lesspipe.sh %s
LESSOPENの動きを確認するため、独自のシェルスクリプトに変更してみる。
$ export LESSOPEN="||/tmp/mylesspipe.sh %s"
独自のシェルスクリプトの中身は、受け取った引数をcat -nするだけ。つまり、行番号つきで第一引数のパスを標準出力するというもの。
$ cat /tmp/mylesspipe.sh cat -n $1 $ chmod +x /tmp/mylesspipe.sh
この状態でlessコマンドを実行してみると、cat -nに対してページャが動いたような実行結果になる。
$ less test.txt 1 1234 2 abcd 3 XYZ test.txt (END)
このことから、LESSOPENで指定されたカスタムのシェルスクリプトが呼ばれ、その出力がlessされていることが分かる。
ということは、話を元のlesspipe.shに戻すと、以下のようにスクリプトを編集し、warやearのときもzipinfoをかますように変えてやれば、lessで中身が見れるようになる!
case "$1" in (・・・略) *.zip|*.jar|*.nbm|*.war|*.ear) zipinfo -- "$1" ;;
まとめ
lessが実際に実行されるとき、LESSOPENという環境変数に定義されたlesspipe.shスクリプトによる処理がかんでいることがわかった。また、このスクリプト自体は様々な形式のファイルに対して「lessしやすいよう」工夫されており、zipがlessでみれるのもその実装の一つにすぎないということだった。さらにlesspipe.shをカスタマイズすれば、より使いやすいオリジナルlessが実現できるかもしれない!
以上