同名コマンドのファイルがなぜ多数存在するのか?スマートな紳士のためのシェルスクリプト(2)(2/2 ページ)

» 2011年12月26日 00時00分 公開
[後藤大地オングス]
前のページへ 1|2       

Mac OS X LionとSolaris 11のケース

 Mac OS Xでも同じように調べてみると、/usr/bin/cdと実体が同じファイルが15個あることが分かる。

% pwd
/usr/bin
% ls -il cd     
3475914 -r-xr-xr-x  15 root  wheel  190  7 21 00:55 cd
% ls -il | grep 3475914
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 alias
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 bg
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 cd
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 command
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 fc
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 fg
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 getopts
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 hash
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 jobs
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 read
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 type
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 ulimit
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 umask
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 unalias
3475914 -r-xr-xr-x   15 root   wheel       190  7 21 00:55 wait
%

 中身もよく似ている。よく似ているというか、この部分はFreeBSDからMac OS Xへマージして使っているので、ほとんど同じだ。ただし、Mac OS Xで使っている大文字と小文字を区別しないファイルシステムでも問題なく動作するように変更が加わっている。Mac OS Xの/usr/bin/cdの中身は次のとおり。コメントにFreeBSDの文字が見える通り、このファイルはFreeBSDから移植したものを変更したものとなっている。

#!/bin/sh
# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
# This file is in the public domain.
builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}

 Solaris 11でも同じことを確認できる。/usr/bin/cdと実体が同じファイルが18個もあるのだ。PC-BSD/FreeBSD/Mac OS Xよりも3つ(test、print、kill)多い。

$ pwd
/usr/bin
$ ls -il cd
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 cd
$ ls -il | grep 87860
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 alias
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 bg
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 cd
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 command
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 fc
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 fg
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 getopts
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 hash
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 jobs
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 kill
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 print
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 read
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 test
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 type
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 ulimit
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 umask
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 unalias
     87860 -r-xr-xr-x  18 root     bin        18224 10月 21日  07:52 wait
$

 Solaris 11の場合はバイナリファイルになっているが、基本的にやっていることは同じだ。組み込みコマンドがlibcmdにまとめられているので、そちらを直接呼び出すか、またはシェルへ処理を引き渡すようになっている。Solaris 10以前はFreeBSDやMac OS Xのようなシェルスクリプトが使われている。

その理由は「POSIX.1準拠」

 なぜこのような「不思議」なシェルスクリプトがシステムに存在しているのか? コミットログ「/head/usr.bin/alias/generic.sh - Revision 100200」を見ると分かりやすい。「A little bit more thought has resulted in a generic script which can implement any of the useless POSIX-required ``regular shell builtin'' utilities, saving one frag and one inode each.」使いものになるかどうかは別として、POSIX.1が要求する標準組み込みユーティリティの機能を実現するためにこの機能を導入しているのだ。

 標準組み込みユーティリティにどのような要求があるかは、「The Open Group Base Specifications Issue 7 - IEEE Std 1003.1-2008」の次の部分の説明を読むと分かるだろう。

 詳しい説明は別の機会に譲るが、POSIX.1ではシェルスクリプトのユーティリティを標準ユーティリティ(レギュラー組み込みユーティリティを含む)と特殊組み込みユーティリティに分けて扱っている。POSIX.1に表記があるものであれば、例えば「break、:、continue、.、eval、exec、exit、export、readonly、return、set、shift、times、trap、unset」などが特殊組み込みユーティリティとなる。

 これ以外のユーティリティは、コマンドが存在するか組み込まれているかにかかわらず標準ユーティリティとなる。標準ユーティリティはexec(3)ファミリから利用できる必要があるほか、その動作を必要とするほかの標準ユーティリティから利用できなければならないという説明がある。実行ファイルが存在するコマンドであればこの条件を満たせるが、組み込みコマンドの場合は、ひと工夫する必要がある。

 シェルスクリプトの実装では実行速度を少しでも上げるために、よく使うユーティリティは組み込みで実装することが多い。例えばPOSIX.1なら「alias、bg、cd、command、false、fc、fg、getopts、jobs、kill、newgrp、pwd、read、true、umask、unalias、wait」などがレギュラー組み込みユーティリティとなっており、事実、組み込みコマンドとして実装されることが多い。

 当然組み込みコマンドはコマンド単体でファイルが存在するということがない。このままではexec(3)から呼ぶことはできない。しかしPOSIX.1はそうした組み込みコマンドに対しても、ファイルが存在するコマンドのようにexec(3)ライブラリから利用できる必要があるとしている

 /usr/bin/cdのようなシェルスクリプトは、まさにこのために存在する。この組み込みコマンドの実行へ置き換えるシェルスクリプトが、ファイルの実体として機能するためexec(3)から利用できるようになる。意味があるかどうかは別として、POSIX.1はそう動作することを要求している。例えばシェルであれば、シェルから「exec cd」のように実行したら、それが問題なく処理されることを求めている。/usr/bin/cdはこうした要望を実現するための合理的で分かりやすい実装というわけだ。

テクニックと標準準拠が詰まったシェルスクリプト

 /usr/bin/cdは短いシェルスクリプトだが、その短いスクリプトの中に、よく使われるテクニックを収録しており、仕組みと仕掛けが面白い。最初に取り上げるには良い対象だろう。短いが適度に難しく、そして意味が分かりにくいので調査を続けるモチベーションにもつながる。最終的にはPOSIX.1にたどり着くので、POSIX.1を読み始める取っ掛かりを得やすい部分ではないかと思う。

 こうしたケースのほかに、組み込みコマンドをコマンドに対応させるテクニックを使うことはあまりないが、システムに理解できないシェルスクリプトがあるというのは気分のよくないものだ。こういう疑問は最初につぶしてしまった方が精神衛生上好ましい。

最後に - Ports Collectionとシステムソースコード

 本稿執筆段階で最新のPC-BSD 9.0はRC3だが、RC3からはシステムソースコードとPorts Collectionがインストール時にまとめてインストールできなかった。このため補足ということで、後からPorts Collectionやシステムソースコードをインストールする方法を紹介しておく。まず、Ports Collectionはroot権限で次のように作業して最新版を取得できる。

portsnap fetch extract update

 いったん取得したら、「portsnap fetch update」を実行すれば最新版に更新できる。システムのソースコードは次のようにsvn(1)コマンドを実行すれば取得できる。

svn co http://svn.freebsd.org/base/releng/9.0 /usr/src

 Gitで取得する方法もある。Gitを使うときは「Git - FreeBSD Wiki」に説明がまとまっているので参考にしてほしい。

著者プロフィール

後藤 大地

オングス代表取締役。@ITへの寄稿、MYCOMジャーナルにおけるニュース執筆のほか、アプリケーション開発やシステム構築、『改訂第二版 FreeBSDビギナーズバイブル』『D言語パーフェクトガイド』『UNIX本格マスター 基礎編〜Linux&FreeBSDを使いこなすための第一歩〜』など著書多数。



前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。