xargs(1)に空の入力を与えたとき、BSD系だと何も実行されないが、Linux(というかGNU)やSolarisなど、BSD系以外だと引数なしでコマンドが実行される。(ただし、GNU xargsは--no-run-if-empty/-rで抑制できる)
SUSv3においても:
The utility named by utility shall be executed one or more times until the end-of-file is reached or the logical end-of file string is found. The results are unspecified if the utility named by utility attempts to read from its standard input.
(下線は筆者)と規定されている。ここでの”shall”は”must”と同義だ。この仕様は実用において煩わしく、論理において美しからぬものだと思うのだが、どうだろう。引数を任意個受け取るコマンドに0個の引数を渡して有意な結果が得られる場合というのがあまり想像できない。たいがいは、以下のいずれかの挙動を示し、つまらない結果になるだろう。
- 引数が足りずエラーになる
- デフォルトのものを対象とする(標準入力から読む、カレントディレクトリを対象とする、など)
よくあるgrep(1)の場合は、xargs grep baa /dev/nullのような定石があって、イテレーションの最後が1引数のみの時の対策が入力が空のときの対策を兼ねてくれる。意味が二重になっているというのは一石二鳥と言える反面、美しくないとも言える。
引数が複数のときだけファイル名を出力する仕様をフラグで制御できればいいが、残念ながらそうしたものはSUSv3には規定されていない。
grepはまだましな方で、「find . -type f -name '*.sh' | xargs -I @ cp -p @ /some/where/」のような場合が厄介だ。cp(1)がコピーに失敗したときの処理に加え、引数がないときの文法エラーまで面倒を見なければならない。
SUSv3を引き合いに出したので省いたが、find(1)の-print0とxargs(1)の-0は必ずセットで付けています。
こうして見ると、シンプルなツールといえども、というかシンプルなツールほど、妥当な仕様を決めることは難しいということが言えそうだ。色々なものと組み合わせて使われるため、最初にすべてを見通すことはできない。多くの場合に便利そうだと思って実装した親切も、後で思わぬ落とし穴になったりする。いずれ突き詰めて再考察してみたい。



DVDとか借りてきて、みんなでわいわい楽しいホームパーティ。ワインの味利きと腕利きシェフがいるので、飲み食いにおいて外れなし。俺はというと適当に買ったものがプチヒットというくらいか。
結局、明け方までパーティーは続いた。Yこちゃんは早々に寝入ってしまったけど、お酒も入っていい気分だったみたい。Rollingはすばらしい仕事を帳消しにしかねない大いびきをかいてくれましたが、ティッシュをふわっと乗せたら静かになった。姫は濡れタオルを主張していたけど、ここは武士の情け。
ああ、明日は試合だよ!がんばって片付けを終えて短い眠りに就いたのでした。楽しくておいしかったね!
先日の抜け駆け事件以来、姫とRollingの二人はすっかりうまいうなぎを食べたい熱が高まっていたが、今日がその念願の予約日。Yこちゃんを誘って四人で向かいます。
荻窪南口の商店街を左に抜け、しばらく歩いて安斎に到着。ここは時間厳守なので注意。予約を入れた時間に合わせて焼き物やご飯の時間をスケジュールしているので、遅れると台無しになってしまう。
少し早めに着いたので、まずはお漬物とお茶をいただく。塩分と水分が体にうれしい。落ち着いたところでビールを注文して乾杯。さっと出てきた骨せんべいも美味で、すばらしいおつまみだ。

すっかり涼んで、食欲がふつふつと沸いてきたところで、タイミングよく白焼きのお出ましだ。
ほんの少しわさびを付けて口に運ぶ。とろけるような舌触りと濃厚なうまみの後に、すーっとわさびが香る。しつこすぎず、淡白すぎず。ビールを含むのがもったいないほどだが、ついつい喉を鳴らせてしまう。たまらず日本酒を注文し、至福のひととき。


そこへ真打ち、うな重と肝吸いの登場。うひー!これはレベルが高すぎ。パサつかず、脂ぎらず、なめらかで上品な身の味わい。むらなく塗られ、照り輝くタレ。もう言うことなし。ご飯がやわらかいのが気になったが、これは好みの問題かな。次は固めでお願いしよう。
いやー、すごいものを食べてしまった。すっかりいい気分になり、みんなだらしなくニコニコ顔をぶらさげて練り歩いてしまった。「うわーまだ7時だよー」「外明るいし!」「もっと飲みたいねー」と、まるで酔っぱらいの御一行。酒よりも、うなぎに酔ってしまったようだ。
そんなこんなで、我がうなぎの寝床で二次会をすることになった。健全な大人すぎてこわいくらいだ。それにつけても、食材やお酒の調達がなんと楽しいことか!
引っ越し元の西荻では近所のモスバーガーがなくなってがっかりな思いをしたが、越してきたら近くにモスバーガーがある。しかもグリーンモス。気だるい休日の昼下がりに利用しない手はない!

ということで、モスバーガーで買ってきて、ミルクティーを入れ、残っていたパンを焼いて遅いブランチ。シーザーサラダでドレッシングをシーザーにするか和風にするかというのは愚問だと思っていたけど、和風にしてみて、こちらの方がうまいとわかった。んむー。

そしてリンゴのパンは余計だった。今夜はすごいものを食べに行くので軽めにしないといけなかったのだけど…。
腹ごなしに掃除をしたりして、夜の大物を迎え入れる準備をしたのでした。
昨日報告したバグが修正され、Encode::EUCJPMS 0.07がリリースされた。ものすごく致命的なバグだったと思うけど、誰も使っていなかったのかな。不思議。
Perl5で丸数字とかを正しく扱うために、Encode::EUCJPMSモジュールを使っている。しかし、0.06だとなぜか「eucJP-ms」エンコーディングが定義されない。テストは以下の簡単なコードで行った。
#!/usr/bin/perl -w
use Encode qw(from_to);
use Encode::EUCJPMS;
#use Encode::Alias;
#define_alias('eucJP-ms' => 'glibc-EUC_JP_MS-2.3.3');
while (<>) {
from_to($_, 'eucJP-ms', 'cp932');
print;
}
0.05では問題なく動くが、0.06だと「Unknown encoding ‘eucJP-ms’ at test.pl line 10」と怒られる。コメント部分を生かすと動くので、エイリアスが効いていないのではないかと思われるが、果たして。
作者の方に質問してみたので回答待ち。
ssh-agent-proxy(1)の0.0.2をリリースします。0.0.1からの主な変更点は以下の通り。
- 作ろうとしたソケットがすでに存在する場合、実際に接続可能かをチェックし、もし接続できなければ削除してソケットを開くようにした。
- すでにdaemonが上がっている場合も環境変数定義を出力するようにした。
- -kでdaemonの削除ができなかった場合は非0のステータスコードを返すようにした。
- -qを新設。重要でないお知らせメッセージの出力を抑制。
これで、ログインスクリプト内に次のように書けばよくなりました。めでたしめでたし。
eval $(ssh-agent-proxy -q 2>/dev/null)
二週間ぶりに、いつもの三人組でホームパーティ。味をしめまくって今日で三回目ですが、今回は手巻き寿司!



週末ながら仕事漬けの俺を置いて、二人が頑張って買い物から支度まで一切合切がんばってくれました。俺は米を炊いたくらい。せっかくなので魚沼産コシヒカリ100%使用。
豪華にそろった数々の具材から、おのおの好きなものを巻いて食べまくる。シャケとアボカドとエビを大葉で巻いてマヨ、とか、うなキュウに梅干し、とか、まぐろ納豆巻き、とか、もう最高。ビールがうまい。キュウリとミョウガの浅漬けや豚の冷しゃぶサラダもいいアクセント。おいしい!たのしい!

「ディープブルー」と「プライドと偏見」の二本の映画を鑑賞し、食後には果物と日本酒を少々。梨と日本酒の相性は抜群で、その花のような軽やかな香りは天にも昇るようです。ああ、夢ごこち。
今日も後片付けは俺の担当でしたが、手巻き寿司は調理で出る洗い物が少ないので楽だった。(・∀・)
これだけ飲んで食って、一人2,500円。安!ますます味をしめちゃうね。次は何にしよう?
土曜の昼下がりはパンを食べようということで、阿佐ヶ谷のパン屋を二つ試してみた。

まず、中杉通りをまっすぐ北上し、中野区との境の手前にある「Bread Art ROAD」。豆腐とかワカメとかを使った変わり種がいろいろある。
写真手前の長方形のがおとうふのパン、左上がりんごのパン、右上がエビとベーコンのパン。
豆腐パンの強烈な存在感が異彩を放っていますが、チーズケーキっぽい感じ。腹にたまるんだかたまらないんだか微妙なボリューム感でしたが、体積と密度の割には意外と軽いかも。
上の二つは食べずに取っておいたので後日。

そこから中杉通りを駅の方にしばらく戻り、「Boulangerie KOCHU」に寄った。炎天下だったのだけど、並木の木陰は涼しくて助かった。店内のシックな雰囲気と、並ぶパンのセンスに期待大。ワインやビールのおともになりそうなパンがいろいろあります。いろいろ買ったけど、すぐ食べたのはこの二つだけ。
右はハムサンドで、外からは見えないが結構バターがたっぷり塗られていてびっくり。でもおいしかった。左はパイナップルとチーズのパンで、意外な相性。翌日のいいおやつになりました。
紅茶は、姫がミルクティーを作ると言うので、ちょうど賞味期限を迎えていた未開封のアッサムを封切り。だいぶ前に国立の「葉々屋」で買ったもの。自分では紅茶を煮出す飲み方をしないので、新鮮でおいしかった。今度は自分で作ってみよう。
ssh-agent(1)の機構はあまりに素朴過ぎて使いづらいので、実用と現実逃避を兼ねてssh-agent-proxy(1)なるものを作った。例によってRubyで書いたプロトタイプだけど、一応動くので公開。
こいつは何かというと文字通りssh-agent(1)のプロクシだが、ポイントは二点。
- それ自身がSSH認証エージェントとして動き、固定パスにソケットを開く。
- クライアントからの接続があると、その場で利用可能な本物のエージェントソケットを探し、通信を中継する。
1により、SSH_AUTH_SOCKには常に固定値を設定すればよくなる。(これはssh-agent(1)でも-aオプションで指定すれば可能) そして2によって、いつでも動的にその時点で利用可能なエージェントソケットを探してつないでくれる。
これがどのように役に立つのかと言えば、たとえばこういうときだ。いつものように、リモートホストにエージェント転送をオンにしてSSH接続したとしよう。そこでscreen(1)を起動し、作業をする。この段階では、問題なくエージェント転送が効いている。ところが、ここで不慮の、あるいは意図的な切断によって、SSH接続が切れてしまったらどうなるか。screeenおよびその子プロセスが持つSSH_AUTH_SOCKは、もはや無効なソケットを指した状態で取り残されてしまう。後で再び同ホストにSSH接続し、保存されたscreenセッションに接続(attach)しても、新しい(転送)エージェントのソケットは使われず、古いSSH_AUTH_SOCKが指すソケットにつなごうとして失敗するだけだ。手で同環境変数の値を更新するしかないが、これはシェル関数(やEmacs用のelisp関数)を用意したとしても非常に面倒な作業だ。
そんな憂鬱も、ssh-agent-proxy(1)を使えば一発で解決する。リモートホストのログインスクリプト内に、次のように書いておく:
eval $(ssh-agent-proxy 2>/dev/null)
これだけ。あとは、勝手にそのときそのとき使えるソケットに中継してくれる。multi-tty版Emacsだけを飼うscreenセッションを裏に置いておけば、いつでもemacsclientで瞬時にエディタが起動し、trampやvcやpclでのSSH接続も無問題。
もちろん、転送元ホストでもssh-agent-proxyを使うメリットはある。もし何らかの理由によって、ssh-agentのインスタンスが死んでしまったりソケットが消えてしまったりしても、慌てずに新しくssh-agentを起動するだけでいい。(もちろん続いてssh-addも必要) 仮にssh-agent-proxy自身が死んでしまったとしても、やはり起動し直せば問題ない。
まだβ版ですが、0.0.1のタグを打っておいたので興味のある人は試してみてください。