はじめに
tr
コマンドの書き方で未だにカッコを付けている書き方をしばしば見ます。
tr '[a-z]' '[A-Z]'
# 補足: 別件の話だがカレントディレクトリに「a」などのファイルがあると
# [a-z] は「a」に展開されるのでクォートは省略してはいけない
このカッコは不要です。
tr a-z A-Z
POSIX.2-1992 でカッコがいらない形に標準化されました。
カッコを付けていると -d
オプションを指定したときに問題が発生します。
$ echo "foo [BAR]" | tr -d '[a-z]'
BAR
無制限にすべての環境にも対応しようと考えると開発コストは増大してしまいます。POSIX に準拠した使い方をしなければ、より多くの環境を考慮しなければいけなくなるので移植性を高めるのがより大変になってしまいます。移植性を重視する場合でも、対応しなくて良い環境(古いバージョンの OS など)は切り捨てて、対応すべき環境を減らすのが開発コストを抑える基本です。「POSIX に準拠した環境にしか対応しない」という方針は現実的な方針の一つです。
旧System Vコマンドから新System Vコマンドへ
カッコが必要だったのは昔の System V 環境です。昔のというのは POSIX に準拠していない環境のことです。POSIX では tr
コマンドを標準化する時、引数の書式については BSD Unix の仕様に統一しました。POSIX は仕様を統一しなければ移植性を高めることが不可能だと考えたからです。
System V 系の Unix、例えば Solaris には複数の tr
コマンドがインストールされています。旧 System V コマンドの tr
コマンドはカッコが必要ですが、新 System V コマンドの tr
コマンドはカッコは不要です。
System V系Unixはデフォルトを互換環境にしていただけ
商用 Unix は POSIX に準拠しています。しかし OS のデフォルト状態(例えばコンピュータを買ってきて起動した状態)で POSIX に準拠しなければならないという要件はありません。なにかの設定を行うことで POSIX に準拠する場合でも POSIX 準拠していると認められます。
POSIX ではコマンド名は標準化されていますが、コマンドをインストールするパスは規定されていません。例えばシェルは POSIX に準拠したシェルは /bin/sh
に配置する必要はなく、/usr/xpg4/bin/sh
に配置しても良いということです。実際に Solaris 10 の /bin/sh
は POSIX に準拠しておらず、POSIX 準拠のシェルは /usr/xpg4/bin/sh
です。そこに配置しても環境変数 PATH
に /usr/xpg4/bin
を加えれば sh
でコマンドが呼び出せるので POSIX 準拠となります。ちなみに POSIX ではシバンはインストール時に適切なパスに書き換えることが想定されています。詳細は sh の APPLICATION USAGE を参照してください。
Solaris では POSIX に準拠した tr
コマンドは /usr/xpg4/bin
と /usr/xpg6/bin
以下にインストールされています。/usr/xpg6/bin
以下にある tr
コマンドのほうがより新しい POSIX 規格に準拠したバージョンです。Solars 11 では /usr/xpg7/bin
ディレクトリもありますが、こちらには tr
コマンドは含まれていません。移植性が重要な場合はユーザーが POSIX 準拠環境に設定して使うことが想定されています。
環境変数 PATH
を POSIX に準拠したものに変更しなければ awk なども古いコマンドが使われます。これは機能が大幅に少ない awk なので移植性を考えるのであれば事実上使い物にならないでしょう。POSIX に準拠したものに変更すれば、旧 System V コマンドを使う必要はありません。
ちなみに Solaris で POSIX 準拠の PATH
を取得する方法として getconf PATH
を使う方法が有名ですが、デフォルトの /usr/bin/getconf
では /usr/xpg7/bin
のパスが取得できません。
$ getconf PATH
/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin
$ /usr/xpg4/bin/getconf PATH
/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin
$ /usr/xpg6/bin/getconf PATH
/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin
$ /usr/xpg7/bin/getconf PATH
/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin
より新しい POSIX のバージョンに準拠する場合は、getconf
を使わずに手動で PATH
を設定する必要があるでしょう。なおこれらは Solaris の場合なので HP-UX や AIX など他の Unix ではドキュメントを参照して正しい方法を使う必要があります。
GNU tr の日本語ドキュメントは古い
GNU tr の日本語ドキュメントにはこのように書かれています。
書式
tr [OPTION]... SET1 [SET2]
中略
CHAR1-CHAR2
CHAR1 から CHAR2 までを昇順に展開した文字列
[CHAR1-CHAR2]
SET1 と SET2 の両方で指定した場合には CHAR1-CHAR2 と同じ
これをもって、GNU tr が認めてるのだからカッコつけてもいいじゃんと思うかもしれませんが、それは日本語版が古いだけで英語版からはこの記述は削除されています。日本語版はどうやら 2016 年頃のもののようです。
さいごに
カッコつけんな!