GNU screen の裏にいる Window で完了したコマンドを Growl 通知したい
というようなことをつぶやいていたら、
Twitter / hchbaw: @typester 最近になって screen -Q windows とできるようになってますね。
と教えていただいた。
-Q
コマンドというのは -X
と同じようなものだけど、コマンド結果を screen 内のステータス領域ではなく標準出力で得ることができる。また、-X
はつねに実行時にそれ自体がアクティブな screen セッションになるのに対し -Q
はアクティブなセッションにクエリを投げる感じで、セッションが切り替わらない。(この辺は理解が怪しいので突っ込み歓迎)
それでそれを使うと
screen -Q windows
と実行することで :windows
で echo されるのとおなじ文字列を標準出力で得ることができる。その出力をパースすれば、自分が screen の裏にいるかどうか判断することができるというわけ。
zsh でコマンド完了時(正確にはプロンプトが表示される直前)に呼ばれるフックは precmd
なので以下のように定義:
function precmd() {
$HOME/bin/precmd.pl `history -n -1 | head -1`
}
シェルスクリプトかけないので Perl に逃げています。 で、precmd.pl は以下のような感じ:
#!/usr/bin/perl
use strict;
use warnings;
use FileHandle;
my $lastcmd = join ' ', @ARGV;
my $window = $ENV{WINDOW};
my $windows = qx{ screen -Q windows } or die "Your screen doesn't support -Q";
qx{ screen -X redisplay };
my $active;
for my $win (split "\x20\x20", $windows) {
my ($num, $flag, $title) = $win =~ /^(\d+)(.)? (.+)/;
if ($flag and $flag eq '*') {
$active = $num;
last;
}
}
if ($window != $active) {
open my $fh, "|/usr/local/bin/growlnotify -t 'GNU screen window $window'" or die $!;
print $fh sprintf 'command done: "%s"', $lastcmd;
print $fh "\n";
close $fh;
}
これで、コマンドが完了した場合にピコーンと通知が来るようになりました。
長い make や wget の時に超絶便利ですね!
書き忘れましたが、現在この機能をつかうためには開発版の screen を使用する必要があります。
mutt の表示がおかしいの直った
前にmutt使っていたときに表示がずれるのよねーとかいってたとき、33rpmさんにslang使えば直るかもとかコメントもらったんだけど、slangにしてもおかしいから放置してたんだけど、どうやらscreenのせいだったっぽい。
screenなしでmutt起動してみたら全然正常だった。。くっそう。
で、そのscreenなんだけど、
ここで配布されているパッチ当てたらmuttまともになった。すばらしー。
ついでにmuttを新しくしてみた。以下作業ログ
mutt:
sudo aptitude install libslang1-utf8-dev
wget http://www.emaillab.org/mutt/1.5.13/mutt-1.5.13.tar.gz
wget http://www.emaillab.org/mutt/1.5.13/patch-1.5.13.mutt-j.ja.1.gz
tar -zxvf mutt-1.5.13.tar.gz
gzip -d patch-1.5.13.mutt-j.ja.1.gz
cd mutt-1.5.13
patch -p1 < ../patch-1.5.13.mutt-j.ja.1
./configure --prefix=/usr/local/mutt --without-wc-funcs --with-slang --enable-default-japanese --enable-hcache
make
sudo make install
screen:
wget ftp://ftp.uni-erlangen.de/pub/utilities/screen/screen-4.0.2.tar.gz
wget ftp://www.dekaino.net/pub/screen/screen-4.0.2-deadlock-patch
wget ftp://www.dekaino.net/pub/screen/screen-4.0.2-hankanacopy-patch
wget ftp://www.dekaino.net/pub/screen/screen-4.0.2-patch-cjkwidth-cvs-2006052001
tar -zxvf screen-4.0.2.tar.gz
cd screen-4.0.2
patch < ../screen-4.0.2-deadlock-patch
patch < ../screen-4.0.2-hankanacopy-patch
patch < ../screen-4.0.2-patch-cjkwidth-cvs-2006052001
./configure --prefix=/usr/local/screen --enable-colors256
# エラーった
sudo apt-get build-dep screen
./configure --prefix=/usr/local/screen --enable-colors256
# まだエラーったconfig.logみる
sudo aptitude install libncurses5-dev
./configure --prefix=/usr/local/screen --enable-colors256
make
sudo make install
256色PuTTY with screen
でけた。
ごろさんのやり方を参考にいろいろ
subtechグループ - 'hceT'.sub(/\Z/,'bus').reverse - putty 256色
- screen の --enable-colors256 のコメントアウトをハズして debuild る
- ncurses-term を入れて /etc/terminfo を れて/usr/share/terminfo の symlink にする←これって大変微妙
- putty の xterm-256 を使うのチェックを入れる
- putty の端末タイプの文字列を xterm-256color に
1やって、2は ncurses-term (terminfo/xterm-256colors用) いれただけ。symlinkはいらねぽい。
3やって、4 は screen しかつかわなかったら変えなくてOk。
これで screen 上で 256color2.pl は通るようになる。
でも emacs, vim ともに TERM=xterm-256colors して起動しないと256にならん。こういうもんかね。
あと、このままだと背景色関係などおかしな部分が出るので .screenrc に
defbce on
と書いて bce モードを ON にする。こうすると vim とかの特定の colorschema で背景がおかしくなるのも治る。bce モードが何かは知らない(ぉ
後こうすると TERM が screen-bce とかになるのでいろいろなスクリプトの書き換えが必要、めんどい。
だめだ、すげー重い。
backtick id lifespan autorefresh command
で autorefresh に 0 以外を指定するとその秒数毎に command が実行されるのだけど、実行されてる間 screen が固まるw
plagger でやるなら Notify::Pipe or Notify::File とかでなんかファイルに書き出しておいて
backtick id 0 0 tail -f そのファイル
かなー。
plagger で backtick
plagger のみで backtick れるじゃんと、miyagawaさんにつっこまれたのでやってみた。
まず Plugin::Notify::Stdout を書いた。
package Plagger::Plugin::Notify::Stdout;
use strict;
use warnings;
use base qw/Plagger::Plugin/;
sub register {
my ( $self, $c ) = @_;
$c->register_hook(
$self,
'publish.feed' => \&update,
'publish.finalize' => \&finalize,
);
$self->{count} = 0;
}
sub update {
my ( $self, $c, $args ) = @_;
$self->{count} += $args->{feed}->count if $args->{feed}->count;
}
sub finalize {
my ( $self, $c, $args ) = @_;
if (defined $self->{count}) {
$self->conf->{format}
? printf $self->conf->{format}, $self->{count}
: print $self->{count};
print "\n";
}
}
ので下記のように backtick.yaml を作る
global:
timezone: Asia/Tokyo
log:
level: error
plugins:
- module: Subscription::Config
config:
feed: "https://username:password@mail.google.com/mail/feed/atom/!!Plagger" # !!Plagger はラベル名
- module: Plagger::Plugin::Aggregator::Simple
- module: Notify::Stdout
config:
format: "Plagger(%d) "
で、あとは .screenrc で
backtick 3 0 60 ${HOME}/plagger/plagger -c ${HOME}/.plagger/config/backtick.yaml
とか書いておけば 60 秒ごとに plagger が実行され、hardstatus とか caption とかで %3` とかけばそこにに plagger の出力が出る。
3 ていうのは backtick で指定した最初の数字 (僕がすでに0 1 2とIDを使ってるので3ってこと)
Gmail の Atom フィードは https + basic 認証
と教えてもらった。!!!
さっき書いたの超意味ない。
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use LWP::UserAgent;
use MIME::Base64;
our $VERSION = '0.02';
# ---- Configurations ----------------
my $username = 'username';
my $password = 'base64::cGFzc3dvcmQ=';
my $label = '!!Plagger';
my $interval = 60;
# ------------------------------------
if ( my ($crypt, $pass) = $password =~ /^(\w+)::(.+)$/ ) {
$password = $crypt eq 'base64' ? decode_base64($pass) : undef;
croak qq/Invalid password crypt type, "$crypt"/ unless $password;
}
my $ua = LWP::UserAgent->new;
my $feed_request =
HTTP::Request->new( GET => "https://mail.google.com/mail/feed/atom/$label" );
$feed_request->headers->authorization_basic( $username, $password );
$|=1;
while (1) {
my $res = $ua->request( $feed_request );
my ($unread) = $res->content =~ m!<fullcount>(\d+)</fullcount>!m;
print "Plagger($unread) \n" if defined $unread;
sleep $interval;
}
これでOKだ。
plagger_backtick.pl
つくた。
こんな感じ。
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use WWW::Mechanize;
use HTTP::Cookies;
use MIME::Base64;
our $VERSION = '0.01';
# ---- Configurations ----------------
my $username = 'username';
my $password = 'base64::cGFzc3dvcmQ=';
my $label = '!!Plagger';
my $interval = 60;
# ------------------------------------
if ( my ($crypt, $pass) = $password =~ /^(\w+)::(.+)$/ ) {
$password = $crypt eq 'base64' ? decode_base64($pass) : undef;
croak qq/Invalid password crypt type, "$crypt"/ unless $password;
}
my $mech = WWW::Mechanize->new( cookie_jar => HTTP::Cookies->new, );
$mech->agent_alias('Windows IE 6');
$|=1;
while (1) {
$mech->get('http://mail.google.com/');
if ( $mech->content =~ /ServiceLoginAuth/ ) {
$mech->submit_form(
fields => {
Email => $username,
Passwd => $password,
}
);
my ($redirect_url) = $mech->content =~ /url=(.*?)"/;
$mech->get($redirect_url);
}
$mech->get("http://mail.google.com/mail/feed/atom/$label");
my ($unread) = $mech->content =~ m!<fullcount>(\d+)</fullcount>!m;
print "Plagger($unread) \n" if defined $unread;
sleep $interval;
}
これ作ってて見つけたんだけど、Gmail の Atom フィードって URL に Label 名つけるとそれで絞り込めるのね。便利!!
jじゃないほうのnaoyaたんのとこからのアクセスが!!
そこのまとめで紹介されてる id:hideoki 製 ssh 設定
function ssh_screen(){
eval server=\${$#}
screen -t $server ssh "$@"
}
if [ x$TERM = xscreen ]; then
alias ssh=ssh_screen
fi
なんだけど、これいいなぁとか思ったけど、screen で ssh 直起動すっと keychain つかえなくねっすか? というのも zshrc で keychain のスクリプトよんでるので、zsh 上で ssh 起動しないといけない。
つか x$TERM = xscreen
て何の意味がw
なので、こないだごろうさんにおしえてもらったのの case cd
のところを
cd|ssh)
if (( $#cmd >= 2)); then
cmd[1]=$cmd[2]
fi
;&
とかしてみた。これでまぁサーバー名(というかsshコマンドの最初の引数)がウィンドウ名になる。
つかそういえば screen 上での keychain についてちゃんと調べようと思ってたはずなのにすっかり忘れてたw