Hibariya

シェルでコマンドの実行前後をフックする

私達の使うアプリケーションは色々な音を出します。通知やエラーを知らせる効果音、たまにジングル (短かい音楽) を鳴らすものもあります。好みや事情によって無効にしている人も少なくないと思いますが、個人的には鳴らせるときには鳴らす方が好みです。なので、毎日使うアプリケーションのひとつであるシェルからも音が出ると楽しいのではないかと思います。例えば、コマンドを実行するときに効果音を出してみたり、失敗したとき ($? -ne 0) には悲しい感じの音が出るとか。もっと発展させて、状況に応じてリアルタイムにサウンドを作り出すとか。

そんな「音の鳴るシェル」作りの一環として、今回はコマンド実行の前後で音を出す方法を考えてみます。どうすればコマンドを叩くタイミングで任意の処理を実行できるのでしょう。1年くらい前に シェルを操作する 記事を書きました。この方法ではシェルの入出力を操作できますが、シェル上で実行されたコマンドの実行結果は得られません。そこで、シェルの機能を使ってコマンドの実行をフックし、コマンドの結果などを取得する方法を調べました。

fish

fish では イベントハンドラ というかたちでコマンド実行前後の処理を実装できます。function 定義にイベントを指定しておくと、イベントが発火されたタイミングでその function が実行されます。この仕組みを利用してコマンド実行前後をフックするには、組込みの fish_preexecfish_postexec イベントが使えます。

function my_preexec --on-event fish_preexec
  echo "preexec: $argv[1]"
end

function my_postexec --on-event fish_postexec
  echo "postexec: $argv[1] ($status)"
end

実行してみましょう。

$ uname
preexec: uname
Linux
postexec: uname (0)
$ hi
preexec: hi
fish: Unknown command 'hi'
postexec: hi (127)

ちなみに function 定義には --on-variable--on-signal というオプションもあり、値の変化やシグナルの受信を監視できて便利そうです。

function my_pwd_changed --on-variable PWD
  echo "PWD: $PWD"
end

function my_term_trap --on-signal SIGUSR1
  echo "SIGUSR1 received"
end

実行結果は次のようになります。

$ cd /tmp/
PWD: /tmp
$ kill -USR1 %self
SIGUSR1 received

zsh

zsh の場合は、add-zsh-hook でフックを登録できます。fish_postexec にあたるものは無いので、プロンプト表示前に実行される precmd を、コマンド実行後のフックとして代用しました。ここには実行したコマンドが渡ってくるわけではないので、もし必要ならばもう少し工夫が要りそうです。

autoload -Uz add-zsh-hook

add-zsh-hook preexec my_preexec
add-zsh-hook precmd my_precmd

my_preexec() {
  echo "preexec: ${1}"
}

my_precmd() {
  echo "precmd (${?})"
}

実行結果です。

% uname
preexec: uname
Linux
precmd (0)
% hi
preexec: hi
zsh: command not found: hi
precmd (127)

bash

bash では bash-preexec を使うと比較的簡単に実現できました。zsh と同様、コマンド実行後のフックは precmd で代用しています。実行結果は zsh の場合とほぼ同じなので省略します。

# https://github.com/rcaloras/bash-preexec
source ./bash-preexec.sh

preexec_functions+=(my_preexec)
precmd_functions+=(my_precmd)

my_preexec() {
  echo "preexec: ${1}"
}

my_precmd() {
  echo "precmd ($?)"
}

おわりに

私がよく使うシェルを対象に、コマンド実行前後をフックする方法について調べました。別の実現方法としては ptrace(2) や DTrace、trap(1) を駆使することで似たようなことができるかもしれません (試してない)。が、私の知っている範囲だとシェルを使うのが比較的シンプルなやり方だと思いました。もしもっと良いやり方があれば教えてください。

2月上旬の出来事

普段使いのバッグを変えた

今までは FJALL RAVEN KANKEN の紺色+黄色のやつを使っていたんだけど、16Lだと少し心細い。PCとヘッドホンケースを入れたらあまりスペースに余裕がなくなってしまう感じ。

新しいのは少し大きめにして MILLET TARN 25 にした。これくらいの大きさだとちょと遠くへ行くにも安心感があっていい。それと、このバッグは上下2部屋に分けられるところがよくて、少し狭い下段の部屋には普段使わないが持っておきたい折り畳み傘とか電源ケーブルみたいなものを突っ込んでおける。

今更だけど FJALL RAVEN は手提げで使うのが便利なのではという気がしてきた。だからこれからも何かと用途はありそう。よかったよかった。

hibariya.org の DNS を Cloudflare に移行した

Cloudflare も API を公開していたので、以前やったような たまに変わるIPアドレスを更新する ためのコードをガガガと書いた。プロセスの管理が面倒なので適当なスケジューラ (Systemd の timer) を使って、決まった時間に叩いている。Systemd の timer は cron に比べて設定が冗長で面倒だと思っていたけど、エラー含めた出力がデフォルトで journal に流れるのはいいな。というのと、こういう用途には実行可能なバイナリ形式が楽そうだなあと思った。

アボカドをハイドロカルチャーにした

アボカドの種を水につけて栽培していたんだけど、色々面倒になってきたので栽培方法をハイドロカルチャーに変えた。容器の底に ミリオンAイオン交換樹脂剤 を入れて、 ハイドロコーン で種を固定したらできあがり。毎日水をかえなくてよくなったし、万一容器を倒してしまっても掃除が楽そう。

ハイドロカルチャーというのは和製英語で、hydro (水) + culture (栽培) ということらしい。cultureに栽培や養殖という意味もあるというのを初めて知った。じゃあ単に水につけて栽培するのも魚の養殖もハイドロカルチャーなんだろうかという気がしてくるが、その辺はよくわからない。水で養殖してるわけじゃないんだから魚は言いすぎか。

Ember.js Tokyo Reborn へ行った

昨日 (2/2) の Ember.js Tokyo Reborn。LT枠もあったので最近 Ember Data まわりの悩みごとについて発表してきました。

何かを削除するアクションをしたとき、即座にサーバへ反映したいけど、そのアクションを起こしたクライアント上ではまだちょっと表示していたい。例えば Twitter の Like 一覧で Unlike してもしばらく残ってるみたいな動きを Ember + Ember Data でやるときに、もっとうまくやれないかなという内容です。

会場では、直接の解決策ではないけど、pouchdb のようなものを使ってうまくやれないかとか、ちょっと違うかもだけど ember-changeset 便利ですよという話を聞けた。便利そう。

その他に気になった話題とか:

近所の Ember ユーザの話を聞ける貴重な時間だったなあ。それとさくらインターネットさんのオフィスから見える夜景たいへんきれいでした。

Android で Pure Data のヘルプを動かす

Pure Data に付属しているヘルプはパッチなので実際に動かしながら理解できて便利。スキマ時間にスマホで触りたい。MobMuPlat は Pure Data のパッチを開けるそうなので試してみたところだいたい動いた。

パッチには次のような感じでちょっと手を加える必要があった (output~dac~ にして、number の幅を広げる)。

sed -i -e 's/output~;/dac~;/g' *.pd
sed -i -re 's/X floatatom ([0-9]+) ([0-9]+) 0 /X floatatom \1 \2 5 /g' *.pd

Android File Transfer を使ってパッチをコピーして MobMuPlat から開くとだいたい動く。線が描画されないのはご愛嬌。

最近読んでよかった本

世界一わかりやすい英語の発音の授業

発音の練習に使っていた「英語耳」の情報を補完するために使ったもの。発音の方法やコツはもちろん、弱系とか、スペルと発音の関係のような便利情報があります。これを知っていれば、はじめてエンカウントする単語の発音もだいたいあたりがつけられて、例えば ceil と cell では e の発音が違うだろうということが、スペルを見ただけで予測できて嬉しい。

嫌われる勇気

ひとつだけ選ぶとすれば「課題の分離」という考え方はすきだなーと思いました。他者の課題に「介入」しないことで、そのぶん、自分から見た世界をシンプルに保てる。これはアドラー心理学というものの本とのこと。デール・カーネギーの著作には「アドラーの思想が色濃く反映されてい」るそうで、ここで改めて「人を動かす」を読み返したりすると少し違う感じに見えておもしろそうです。

なぜ、決算書が読めるヤツは出世するのか

財務諸表を読めるようになる必要を感じていたので手頃なお値段なものを購入。おおざっぱには読めるようになりました。出世の役に立ちそうかというと怪しいけど、例えば株式投資とか就職先を決めるときには有用そう。最近は貸借対照表の代わりに財政状態計算書が使われているそうです。

あなたの話はなぜ「通じない」のか

聞き手は話し手のメッセージを受け取るとき、話し手の言葉だけでなく「メディア力」も考慮する。自分の聞いてもらいたいことを聞いてもらうには、相応のメディア力が必要、という話。別の人が言うと注目されるけど「私」が言っても流されるとか、ちゃんと説明しているつもりなのに全然伝わってなかったとか。それは現在の「私」のメディア力というか、メディアとしての性質が、「私」の思っているものと違うからなのかもしれない。

なぜ、この人と話をすると楽になるのか

非・仕事のコミュニケーションは「気まずさ」を相手に戦う協力プレイのゲームだよ、とのこと。ゲームなら何度かやってるうちに少しは上手になるかもしれない。

ひとこと

タイトルに「なぜ」が入ってる本を3冊も読んでしまったのでしばらくは違う感じのものを読もうと思いました。