Cygwin の ssh は便利なんだけど日本語が通らないのが玉に傷。というか通るけ ど EUC 表示されてもうれしくないので、なんとか sjis に変換したい。
というわけで、作ってみました jssh.pl です。 なお Jcode モジュールが必要です。cygwin には Jcode モジュールが入ってい ないけど perl -MCPAN -e shell として、出てきたプロンプトに install Jcode と入れるだけ。なんとらく。
ポイント: 入力コードは euc を指定することで、速度向上&判定ミス回避。
#!/usr/bin/perl use Jcode; open(CONV_IN, "-|") or exec ('ssh', @ARGV); $| = 1; my $jconv = new Jcode; while(defined ($k = getc(CONV_IN))) { if( $k =~ /[\x80-\xff]/ ) { $k = $jconv->set($k . getc(CONV_IN),'euc')->sjis; } print $k; }
をを変換する。一応。でもなんかおそくないですか。あと標準エラー出力もなん とかなりませんか。ということでもうちょっとがんばってみちゃいました。
ポイント: pipe+fork を使って、標準出力と標準エラー出力をいっしょにしちゃ う。それと、getc をやめて sysread を使うことで、perl の行ごとのバッファ リングを回避する。 漢字の半切れ出力を避けるために正規表現で検査、最後の半端バイトは次回に回 す。
#!/usr/bin/perl use Jcode; pipe(CONV_IN, SSH_OUT); if( ($pid = fork) == 0) { close CONV_IN; close STDERR; close STDOUT; open(STDERR, ">&SSH_OUT"); open(STDOUT, ">&SSH_OUT"); exec ('ssh', @ARGV); } close(SSH_OUT); $| = 1; my $jconv = new Jcode; $kondo = $tsugi = ""; while( sysread(CONV_IN,$in,30000) ) { if( ord(substr($in,-1)) >= 128 ) { # $in の最後が漢字に相当するバイトの場合 (正規表現が重たいので) if( $in =~ /(^|[^\x80-\xff])([\x80-\xff][\x80-\xff])*([\x80-\xff])$/ ) { # $in の最後に漢字に相当するバイトが 2n+1 個ある場合、 # その最後の 1 つを次にまわす $tsugi = $3; $in = substr($in, 0, -1); } } print $jconv->set($kondo.$in, 'euc')->sjis; $kondo = $tsugi; $tsugi = ""; } waitpid($pid, 0);
かんぺきです。関係ないけど電車の時刻の「こんど」「つぎ」ってわかりにくい よね(ってそれを真似するな)。
※ 2004/2/26 追記: cygwin 上なら cocot というのができました。こっちのほうがよっぽど便利です。