SSHだけでリモートサーバからローカルMacにGrowl通知したい!

Growlしたい!というときは次のようにやってます。

概要

  1. リモートでgrowl専用のログファイルを準備する。
  2. ローカルからリモートにsshで接続し、tail -fでログファイルの監視する。
  3. リモート側では、そのログファイルに対してGrowlさせたい内容をリダイレクトを使って追記する
  4. 追記された内容が出力されるので、その出力をローカルのLLで行ごとに読み込む。
  5. 読み込んだ行を growlnotify を起動して通知する

これだけ。

growlnotify が必要なので、 GrowlのディスクイメージのExtrasフォルダから事前にインストールしておくこと。

手順

ステップ1 - リモートで
$ echo 'foo' > $HOME/growler.log 

このように、ログファイル(通知させたい内容を追記するファイル)を作成しておく。

ステップ2 - ローカルで
$ ssh example@example.com tail -n 1 -f '$HOME/growler.log' | perl -e 'system "growlnotify", "-m",  $_ while (<STDIN>);'

この例では、example.comsshでログインし、ログファイルをtail -f で監視する。
標準出力がpipeによってperlに流れるので、それを受信してgrowlnotifyを起動する。
これによってファイルの最終行がgrowlされ、接続できているか確認できる。

ステップ3 - リモートで
$ echo 'hoge' >> $HOME/growler.log
$ ls >> $HOME/growler.log

このように標準出力をログファイルに追記するだけでgrowl通知ができる!

応用

とても時間のかかる処理をさせている間に別の処理をしたい場合
cpan-outdated -p | cpanm; echo 'upgraded' >> $HOME/growler.log

としておくと、処理が終わったときに通知してくれます。

ログファイルを吐き出すIRCクライアント(この場合はweechat)をリモートのscreen上で実行している場合
ssh example@example.com tail -n 1 -f '$HOME/.weechat/logs/*/*/*.weechatlog' | perl irc_growl.pl &

としてサーバにつなげ、irc_growl.plで処理を加えた上でgrowlさせることもできる。irc_growl.plでは、 --appIcon にLimeChatを指定することでGrowl時のアイコンを変更している。

sshのコマンドが長いと感じたら、.bashrcにaliasを設定しておくと良い。
参考にirc_growl.plを貼りつけておく。

irc_growl.pl
while (<STDIN>) {
    chomp;
    next unless $_;
    next if /^==>/; # ignore tail's output

    my $attr = parse($_);
    if ($attr->{type} =~ /(:?NOTICE|PRIVMSG)/) {
        system("growlnotify", "-m", $attr->{content}, "-t", $attr->{user}, "--appIcon", "LimeChat");
    }
}

sub parse {
    my ($line) = @_;

    my ($time, $cmd, @contents) = split /\t/, $line;
    my $content = join "\t", @contents;

    my $user;
    if (not $cmd) {           # critical error
        $cmd = 'ERROR';
    } elsif ($cmd eq '-->') { # join
        $cmd = 'JOIN';
    } elsif ($cmd eq '<--') { # part
        $cmd = 'PART';
    } elsif ($cmd eq '--') {  # messages from server
        $cmd = 'SERVER';
    } elsif ($cmd eq '*') {   # notice
        $user = $cmd;
        $cmd = 'NOTICE';
    } else {                  # privmsg
        $user = $cmd;
        $cmd = 'PRIVMSG';
    }

    return +{
        type    => $cmd,
        time    => $time,
        content => $content,
        user    => $user,
    };
}

やっぱりTCPでネットワーク通知したい場合

私の場合はこれで困ってないのでしらべてない。

sugyanさんが週末を犠牲にしてまで調べているのでしばしお待ちを!!