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 というのができました。こっちのほうがよっぽど便利です。