less の意外な使い方
会社のバイト君(兼、僕の先生)と一緒に less って無駄に高機能だよねという話が出たので紹介。僕は最近まで知らなかったのですが、意外に知ってる人多いかも?
一般的にページャーとして用いられている less ですが、実は以下のような使い方ができたりします。
% less /bin/sh ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x805bdd0 Start of program headers: 52 (bytes into file) Start of section headers: 654192 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 9 Size of section headers: 40 (bytes) Number of section headers: 27 Section header string table index: 26 ...
見ての通り、 /usr/sh をバイナリとして less するのではなく、 /usr/sh の objdump の結果を less しています。また、それに加えて、 .so や .tar.gz 、``.ps`` 、 .pdf 、 .png 、 .mp3 などさまざまな種類のファイルを求められるであろう情報に変換したものを less することができます。
それで、実際どうなっているのかというと、 less がファイルを開くときに LESSOPEN 環境変数を読みこんで、その値をフィルタプログラムとして起動することで less する内容を変化させられるようになっています。
僕の環境では以下のようになっています。
% echo $LESSOPEN |lesspipe.sh %s % type lesspipe.sh /usr/bin/lesspipe.sh
/usr/bin/lesspipe.sh:
#!/bin/bash # # Preprocessor for 'less'. Used when this environment variable is set: # LESSOPEN="|lesspipe.sh %s" # TODO: handle compressed files better trap 'exit 0' PIPE guesscompress() { case "$1" in *.gz) echo "gunzip -c" ;; *.bz2) echo "bunzip2 -c" ;; *.Z) echo "compress -d" ;; *) echo "cat" ;; esac } lesspipe_file() { local out=$(file -L -- "$1") case ${out} in *" ar archive"*) lesspipe "$1" ".a" ;; *" tar archive"*) lesspipe "$1" ".tar" ;; *" CAB-Installer"*) lesspipe "$1" ".cab" ;; *" troff "*) lesspipe "$1" ".man" ;; *" shared object"*) lesspipe "$1" ".so" ;; *" Zip archive"*) lesspipe "$1" ".zip" ;; *" LHa"*archive*) lesspipe "$1" ".lha" ;; *" ELF "*) readelf -a -- "$1" ;; *": data") hexdump -C -- "$1" ;; *) return 1 ;; esac return 0 } lesspipe() { local match=$2 [[ -z ${match} ]] && match=$1 local DECOMPRESSOR=$(guesscompress "$match") case "$match" in ### Doc files ### *.[0-9n]|*.man|\ *.[0-9n].bz2|*.man.bz2|\ *.[0-9n].gz|*.man.gz|\ *.[0-9][a-z].gz|*.[0-9][a-z].gz) local out=$(${DECOMPRESSOR} -- "$1" | file -) case ${out} in *troff*) # Need to make sure we pass path to man or it will try # to locate "$1" in the man search paths if [[ $1 == /* ]] ; then man -- "$1" else man -- "./$1" fi ;; *text*) ${DECOMPRESSOR} -- "$1" ;; *) # We could have matched a library (libc.so.6), so let # `file` figure out what the hell this thing is lesspipe_file "$1" ;; esac ;; *.dvi) dvi2tty "$1" ;; *.ps|*.pdf) ps2ascii "$1" || pstotext "$1" || pdftotext "$1" ;; *.doc) antiword "$1" || catdoc "$1" ;; *.rtf) unrtf --nopict --text "$1" ;; ### URLs ### ftp://*|http://*|*.htm|*.html) for b in links2 links lynx ; do ${b} -dump "$1" && exit 0 done html2text -style pretty "$1" ;; ### Tar files ### *.tar) tar tvvf "$1" ;; *.tar.bz2|*.tbz2|*.tbz) tar tjvvf "$1" ;; *.tar.gz|*.tgz|*.tar.z) tar tzvvf "$1" ;; ### Misc archives ### *.bz2) bzip2 -dc -- "$1" ;; *.gz|*.z) gzip -dc -- "$1" ;; *.zip) unzip -l "$1" ;; *.rpm) rpm -qpivl --changelog -- "$1" ;; *.cpi|*.cpio) cpio -itv < "$1" ;; *.ace) unace l "$1" ;; *.arc) arc v "$1" ;; *.arj) unarj l -- "$1" ;; *.cab) cabextract -l -- "$1" ;; *.lha|*.lzh) lha v "$1" ;; *.zoo) zoo -list "$1" ;; *.7z) 7z l -- "$1" ;; *.a) ar tv "$1" ;; *.so) readelf -h -d -s -- "$1" ;; *.mo|*.gmo) msgunfmt -- "$1" ;; *.rar|.r[0-9][0-9]) unrar l -- "$1" ;; *.deb|*.udeb) if type -p dpkg > /dev/null ; then dpkg --info "$1" dpkg --contents "$1" else ar tv "$1" ar p "$1" data.tar.gz | tar tzvvf - fi ;; ### Media ### *.bmp|*.gif|*.jpeg|*.jpg|*.pcd|*.pcx|*.png|*.ppm|*.tga|*.tiff|*.tif) identify "$1" || file -L -- "$1" ;; *.avi|*.mpeg|*.mpg|*.mov|*.qt|*.wmv|*.asf|*.rm|*.ram) midentify "$1" || file -L -- "$1" ;; *.mp3) mp3info "$1" || id3info "$1" ;; *.ogg) ogginfo "$1" ;; *.flac) metaflac --list "$1" ;; *.iso) isoinfo -d -i "$1" ; isoinfo -l -i "$1" ;; *.bin|*.cue) cd-info --no-header --no-device-info "$1" ;; ### Source code ### *.awk|*.groff|*.java|*.js|*.m4|*.php|*.pl|*.pm|*.pod|*.sh|\ *.ad[asb]|*.asm|*.inc|*.[ch]|*.[ch]pp|*.[ch]xx|*.cc|*.hh|\ *.lsp|*.l|*.pas|*.p|*.xml|*.xps|*.xsl|*.axp|*.ppd|*.pov|\ *.diff|*.patch|*.py|*.rb|*.sql|*.ebuild|*.eclass) # Allow people to flip color off if they dont want it case ${LESSCOLOR} in [yY][eE][sS]|1|true) LESSCOLOR=1;; [nN][oO]|0|false) LESSCOLOR=0;; *) LESSCOLOR=1;; # default to colorize esac [[ ${LESSCOLORIZER+set} != "set" ]] && LESSCOLORIZER=code2color if [[ ${LESSCOLOR} == "0" ]] || [[ -z ${LESSCOLORIZER} ]] ; then # let less itself handle these files exit 0 fi # Only colorize if we know less will handle raw codes for opt in ${LESS} ; do if [[ ${opt} == "-r" || ${opt} == "-R" ]] ; then ${LESSCOLORIZER} "$1" break fi done ;; # May not be such a good idea :) # ### Device nodes ### # /dev/[hs]d[a-z]*) # fdisk -l "${1:0:8}" # [[ $1 == *hd* ]] && hdparm -I "${1:0:8}" # ;; ### Everything else ### *) # Sanity check [[ ${recur} == 2 ]] && exit 0 # Maybe we didn't match due to case issues ... if [[ ${recur} == 0 ]] ; then recur=1 lesspipe "$1" "$(echo $1 | tr '[:upper:]' '[:lower:]')" # Maybe we didn't match because the file is named weird ... else recur=2 lesspipe_file "$1" fi exit 0 ;; esac } if [[ -z $1 ]] ; then echo "Usage: lesspipe.sh <file>" elif [[ $1 == "-V" ]] ; then Id="cvsid" cvsid="$Id: lesspipe.sh,v 1.16 2006/07/30 17:36:01 vapier Exp $" cat <<-EOF $cvsid Copyright 2001-2005 Gentoo Foundation Mike Frysinger <vapier@gentoo.org> (with plenty of ideas stolen from other projects/distros) EOF less -V elif [[ $1 == "-h" || $1 == "--help" ]] ; then cat <<-EOF lesspipe.sh: preproccess files before sending them to less Usage: lesspipe.sh <file> lesspipe.sh specific settings: LESSCOLOR env - toggle colorizing of output LESSCOLORIZER env - program used to colorize output (default: code2color) Run 'less --help' or 'man less' for more info EOF elif [[ -d $1 ]] ; then ls -alF -- "$1" else recur=0 lesspipe "$1" 2> /dev/null fi
/usr/bin/lesspipe.sh は Gentoo の中の人が書いた物らしいのですが、 file などを駆使していて、かなり多くの形式を認識できるようになっています( html の取得は wget だろ普通…)。画像ファイルは画像ファイル情報じゃなくて AA 化したものを表示したものを less したいとかいう場合は、 AA 化プログラムを拾ってくるなり作るなりして
*.bmp|*.gif|*.jpeg|*.jpg|*.pcd|*.pcx|*.png|*.ppm|*.tga|*.tiff|*.tif) identify "$1" || file -L -- "$1" ;;
を
*.bmp|*.gif|*.jpeg|*.jpg|*.pcd|*.pcx|*.png|*.ppm|*.tga|*.tiff|*.tif) iamge2aa "$1" || file -L -- "$1" ;;
とでもやれば動くでしょう。
でまあ、件のバイト君とも話していたのですが、これはやりすぎだろうと思うのです。バイナリなら cat -v ぐらいが適切なんじゃないのかと。それよか lv 使っている現状を可及的に解決すべきでしょう。
ちなみに GNU less のソース読んでみましたが、なんとも言えないものでした。
- Category(s)
- linux
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/matsuyama/less-functions/tbping