低レベルインターフェースと高レベルインターフェース

  • ref:J

結局インターフェースの問題なのでは。
単機能のコマンドを組み合わせて、複雑な処理を組み合わせるってのは組み合わせ方次第で、いろんなことが出来るようになるという点で優れてはいるんだけど、そりゃ毎回おんなじことやっていりゃ面倒だし、1つのコマンドで実行できたほうが簡単ではある。gzip/bzip2 と tar だって、みんな GNU tar の場合 -z オプションとか -j オプションとか使うよね(最近は GNU tar はファイルの中身をみて自動認識するからつけなくても展開できるけど)。いちいち明示的にパイプしない。まぁ、そもそもあれが GNU tar の独自拡張オプションだということ自体知らない人が多いけど(そんでもって GNU tar じゃない環境にいくとたちまちアーカイブを展開できなくなる)。
でだ。実は、悪いのは組み合わせないことじゃなくて、組み合わせにくいことなんじゃないだろうか。美しさとかそういう問題じゃなくて。
たとえば、grep が「指定ディレクトリ以下のファイルから特定のパターンを検索する」コマンドなら検索ファイルの条件を指定したい場合は grep を拡張するしかないわけだけど、そうじゃないから find と組み合わせて複雑なことが出来るわけだ。要するに再利用性の問題。
同じことはプログラミングにもいえて、いきなりモノリシックに機能を1つの関数に作りこむんじゃなくて、単純な機能を複数作って組み合わせて高レベルインターフェースを構築したほうが再利用性は高いし、柔軟性も高い。
で、grep と find の問題は適当に Facade 的なものを用意すれば使いやすくなっていいんじゃね、とか思ったので、ちょっと作ってみた。

#!/bin/bash

function usage {
    help_message="Usage: $0 path [grep_args] [-- [find_args]]"
    if [ "$1" -eq 0 ]; then
        echo "$help_message"
    else
        echo "$help_message" 1>&2
    fi

    exit "$1"
}

if [ $# -eq 0 ]; then
    usage 2
elif [ "$1" = "--help" -o "$1" = "-h" ]; then
    usage 0
fi

declare -a grep_args
declare -a find_args

path="$1"; shift

while [ $# -gt 0 ]; do
    arg="$1"; shift
    if [ "$arg" = "--" ]; then
        break
    else
        grep_args[${#grep_args[@]}]="$arg"
    fi
done

if [ ${#grep_args[@]} -eq 0 ]; then
    # grep args not found
    usage 2
fi

while [ $# -gt 0 ]; do
    arg="$1"; shift
    find_args[${#find_args[@]}]="$arg"
done

find "$path" -type d \( -name .svn -o -name CVS -o -name RCS \
    -o -name _darcs -o -name blib \) -prune \
    -o -type f "${find_args[@]}" -print | perl -ne 'chomp; print $_, "\0" if -T' | \
    xargs -0 -e grep "${grep_args[@]}" -- /dev/null

こんな感じで使う。

grep-find . background-image -- -name "*.css"

プライド

例の韓国のテレビ番組で、「悪い子としたときは日本人のふりをするんだ」みたいな発言があったということに対して「プライドがない」とか「恥知らず」みたいなコメントは少なくないと思うんだけど、それはちょっと違うんじゃないかなぁ、と思う。
何をもって「恥」とするかは、その人間が属するコミュニティが持つ倫理観が規定するものなはずで、その倫理観が国際的に見ても変、という指摘ならともかく、全然違う文化を持つ人間に対して「恥知らず」と断ずる行為は、単に自分の価値観を普遍的なものとしてみているに過ぎないんじゃないかな。

UTF-8 でいいよ

いや、もう新規のテキストデータはみんな UTF-8 でいいよ。というか UTF-8 で十分。/.J でも言われているけどフォントの切り替えしたいなら、もっと上のレイヤでやればいいんだよ。
サイズが大きくなるとかいう指摘に関しては論外だよなぁ。ハードディスク上の全てのテキストデータを UTF-8 から MS932*1 に変換したところで、どれだけサイズの節約になるという話だよ。
で、どうでもいいけど、/.J の以下のコメントのボケっぷりはある意味秀逸だと思った。

UTF-8で十分じゃないからUTF-16があるんじゃないの?

*1:いわゆるShift-JIS。ちょっと違うけど

charset と encoding

どういう経緯でそうなったかは知らないが、現状 Web ページのエンコーディングをブラウザに通知するには HTTP レスポンスヘッダの Content-type に

Content-type: text/html; charset=utf-8

といった感じに、エンコーディングを指定することになっている。
で、以前から疑問なんだが、なんで encoding じゃなくて charset なんだろう。いや、だって EUC-JP も MS932/Shift-JIS も ISO-2022-JP もみんな JISX 0208 の上のエンコーディング方式な訳で、charset は一緒じゃん、とか思うのだ。
それとも、charset と encoding をひとまとめにして charset と呼称しているんだろうか?それはそれでややこしいような。
いや、単に1つの文字集合に対して複数のエンコーディングが存在する日本の方が異常なのか。でも、Unicode 化が進むとすれば charset というパラメータ名は現実から乖離していくことになるなぁ。

標準出力の複製

「パイプの途中経過を観察するのために、標準出力を標準エラー出力にコピーしたいんだけどいい方法知っている?」と聞かれたので、

% seq 10 | tee /dev/stderr | cat -n > out

みたいな方法を紹介してみたわけだが、これってどれくらいの可搬性があるんだろう。まぁ、確実なのは

% seq 10 | perl -ne 'print STDERR; print' | cat -n > out

か。でも普通はファイルに出して tail -f だよな。