LoginSignup
80
24

More than 5 years have passed since last update.

Mac のターミナルに `CAL` と打ち込んだときの挙動を追った話

Last updated at Posted at 2016-11-21

みなさん、こんにちは。

最近、曜日や日付の感覚とかがあまり意識できない不健康な生活をしております。 @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

なんと、 calCAL ではカレンダーが転置するという知らなかった挙動をしているもんで、ビビりまくりでしたわ。
訳わかんなくて、取りあえず 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 ではなくても calcal ではない名前で起動すると ncal という cal を転置するコマンドの動作になるということを教えていただきました。

所感

大文字と小文字を区別しない状態でフォーマットした HFS+ は便利なんだか不便なんだか分からないし、転置された cal(1) の出力が同じバイナリを大文字で呼び出すと出てくるって、誰か得してるんですかね…ってか、どこかで使われてるの?

あと、私、ここまで久しぶりにターミナルの挙動で「???」ってなったの、すごい久しぶりなんですけど、世の中の普通のエンジニアはこういうことが発生してもビビらないくらい賢いんでしょうかね…なんか、自分の将来が心配になってきます…

ヒマなときに FreeBSD あたりで cal(1) のコードを読んでみようと思います。

80
24
13

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
80
24