2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェル芸Advent Calendar 2023

Day 10

trコマンドを使うものに物申す、カッコつけんな!

Posted at

はじめに

tr コマンドの書き方で未だにカッコを付けている書き方をしばしば見ます。

昔の書き方(1990年頃までの一部の環境用)
tr '[a-z]' '[A-Z]'

# 補足: 別件の話だがカレントディレクトリに「a」などのファイルがあると
# [a-z] は「a」に展開されるのでクォートは省略してはいけない

このカッコは不要です。

今の書き方(1990年代以降に統一された)
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 年頃のもののようです。

さいごに

カッコつけんな!

2
1
0

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?