みなさん、こんにちは。
最近、曜日や日付の感覚とかがあまり意識できない不健康な生活をしております。 @takano32 です。
そんな私は月曜日とか休日明けとかによくターミナルに cal
って打ち込んで日付を確認したりします。
date
でもいいし、 Mac なら右上に日付が出ていたりするわけですが、習慣なんだからしょうがない。
ところがですね。今日、Mac の仮想端末に Caps Lock が入ったまま CAL
と打ってしまったんですよ。
「ノー、サッチコマ…えっ?なんかカレンダーでてる!」というね。
そこまでなら「あー、HFS+ のファイルシステムってデフォルトのフォーマットでは大文字と小文字を区別しないから、小文字の cal
が呼ばれたのかな」って思うわけですが、よく見ると変なんですよ。
小文字 cal
と 大文字 CAL
の出力
小文字 cal
のカレンダーはこんな感じ
$ cal
11月 2016
日 月 火 水 木 金 土
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
大文字 cal
のカレンダーはこんな感じ
$ CAL
11月 2016
月 7 14 21 28
火 1 8 15 22 29
水 2 9 16 23 30
木 3 10 17 24
金 4 11 18 25
土 5 12 19 26
日 6 13 20 27
なんと、 cal
と CAL
ではカレンダーが転置するという知らなかった挙動をしているもんで、ビビりまくりでしたわ。
訳わかんなくて、取りあえず CAL
を探してみました。
大文字の CAL
はどこにある?
$ which -a CAL
/usr/bin/CAL
なるほど?いや、でもおかしいでしょ。/bin
に大文字のコマンドなんか普通ない。
小文字の cal
についても念のため確認してみます。
$ which -a cal
/usr/bin/cal
ほう。じゃあ、なんだ、大文字の CAL
があるのか?と man CAL
してみました。
$ man CAL
No manual entry for CAL
は?ないの?
・・・
落ち着いて /usr/bin/CAL
から読めそうな部分を以下のような形で出してみました。
$ strings /usr/bin/CAL | less
先頭の方を読んでみると
$FreeBSD: src/lib/libcalendar/calendar.c,v 1.4 2001/09/30 21:09:57 dillon Exp $
$FreeBSD: src/lib/libcalendar/easter.c,v 1.5 2001/09/30 21:09:57 dillon Exp $
@(#)PROGRAM:cal PROJECT:misc_cmds-33
setlocale
POSIX
ASCII
US-ASCII
Jejm:ops:wy
%s: invalid country code
year %d not in range 1..9999
%s is neither a month number (1..12) nor a name
%c%s %-15s%4d-%02d-%02d %c%s %-15s%4d-%02d-%02d
ん、これは小文字の cal
と同じライブラリを使っているということか?と思ったりしたわけですが、後半まで読むと何かおかしいことに気づきました。
usage: cal [-jy] [[month] year]
cal [-j] [-m month] [year]
ncal [-Jjpwy] [-s country_code] [[month] year]
ncal [-Jeo] [year]
いやいや、これは man cal
するとでてくる小文字 cal
のヘルプだぞ。
再び HFS+ は大文字と小文字を区別しないな、ということを思い出し、もしかして ls
がファイルシステムから探してきたときに大文字でも小文字でもヒットしてしまうのか、という予感がしてきます。
それを確認します。
% ls -al /usr/bin/CAL
-r-xr-xr-x 1 root wheel 31824 10 21 18:07 /usr/bin/CAL
大文字のバイナリがリストされました。
$ ls -al /usr/bin/cal
-r-xr-xr-x 1 root wheel 31824 10 21 18:07 /usr/bin/cal
ここでバイナリのサイズが同じことに気づきました。 i-node 番号が同じなんでは?という推測になりました。
$ ls -i /usr/bin/cal
47343084 /usr/bin/cal
$ ls -i /usr/bin/CAL
47343084 /usr/bin/CAL
ビンゴ。
しかし、ハードリンクしているのか?気持ち悪くないか?という疑念に駆られます。
まあ、見れば分かることよ、と見てみると。
$ ls -li /usr/bin/cal
47343084 -r-xr-xr-x 1 root wheel 31824 10 21 18:07 /usr/bin/cal
1 です。つまり、ハードリンクはされていない、ということですね。
じゃあCAL
よ、お前はどこの誰でどういうことなんだ、というと「HFS+ は大文字と小文字を区別しない」ので同じものなんですね。つまり 大文字のCAL
を呼び出したときは小文字のcal
が呼ばれているってことですね。すなわち HFS+ の標準的なフォーマットで大文字のコマンド呼び出しと小文字のコマンド呼び出しは区別されず、コマンドが呼ばれる ってだけです。まあ、これは Mac のターミナルで LS
とか打てば分かります。ちゃんと ls
と同じ出力がでます。そして、今回ここまで調べてしまった元凶としては Mac の cal(1)
は大文字で呼び出すと小文字の呼び出しとは挙動が変化するということだったんですね。何その機能…
えっ、でもわざわざこんな挙動が用意されているということは CAL
って普通の Linux でも使えるのか?と思ったので、今度は Ubuntu で CAL
を使おうとしてみました。
$ CAL
-bash: /usr/bin/CAL: No such file or directory
ないです。そんなモノはないと言っております。
ふーむ。もしかして、自身のファイル名によって挙動が異なるバイナリという busybox のような挙動になっているのでは?と思ったりしたので試してみました。Ubuntu の cal(1)
も man cal
すると BSD 由来であることが分かりますのでその可能性はなくはなさそうです。
$ sudo ln /usr/bin/{cal,CAL}
$ CAL
11月 2016
日 6 13 20 27
月 7 14 21 28
火 1 8 15 22 29
水 2 9 16 23 30
木 3 10 17 24
金 4 11 18 25
土 5 12 19 26
なんと Mac で CAL
をしたときと同じ挙動をしました。
その後、Ubuntu に作成した大文字のハードリンク CAL
はスタッフがおいしく sudo rm -f
しました。
追記
コメントにて CAL
ではなくても cal
を cal
ではない名前で起動すると ncal
という cal
を転置するコマンドの動作になるということを教えていただきました。
所感
大文字と小文字を区別しない状態でフォーマットした HFS+ は便利なんだか不便なんだか分からないし、転置された cal(1)
の出力が同じバイナリを大文字で呼び出すと出てくるって、誰か得してるんですかね…ってか、どこかで使われてるの?
あと、私、ここまで久しぶりにターミナルの挙動で「???」ってなったの、すごい久しぶりなんですけど、世の中の普通のエンジニアはこういうことが発生してもビビらないくらい賢いんでしょうかね…なんか、自分の将来が心配になってきます…
ヒマなときに FreeBSD あたりで cal(1)
のコードを読んでみようと思います。