POSIX準拠とは本当はどういうことなのか？「POSIXで規定されたものだけを使う」ではありません

## POSIX 準拠とは

「**POSIX準拠**」とは移植性を高めるための POSIX が定義した要件を満たすことです。**Linux/Unix用の多数のソフトウェアは POSIX に準拠**しており、多くの環境での動作を実現しています。POSIX の要件には OS ベンダー向けとアプリケーションの開発者向けの要件があり、高い移植性の実現には双方が POSIX の要件を満たして開発する必要があります。POSIX が目標とする移植性とは実行ファイルのバイナリがそのまま動くことではなく「[ソースコードレベルの移植性](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/V1_chap01.html)」です。つまり **「アプリケーションの移植性が高い」とは別の環境でのビルドとインストールが容易である**という意味です。例えば cURL、SQLite、bash などは POSIX 準拠のソフトウェアの例で、数多くの OS で動作しているという事実は POSIX 準拠であることの証明です。現在、数えきれないほど多くのソフトウェアが高い移植性を実現しながらも高い性能、機能性、生産性、互換性などを両立させています。今や特定の環境でしか動かないソフトウェアはほとんどありません。それは各 OS や言語やライブラリが成熟し POSIX に従って作るのがとても簡単になったからです。移植性が高いソフトウェアを利用して作られたソフトウェアもまた移植性が高くなります。POSIX の範囲で作るというのは **最終的に呼び出す OS のインターフェースが POSIX で標準化された API であること**です。したがって POSIX 外のコマンドや Python、Ruby、Rust、JavaScript、Java などのさまざまな言語で作ったアプリケーションも（間接的に）POSIX インターフェースを呼び出しているなら「POSIX 準拠」と言えます。事実それらを使って作られたアプリケーションは高い移植性と互換性があり、どの環境でも動きます。現在のソフトウェア開発は多数の POSIX 準拠の言語やライブラリやフレームワークやミドルウェア等に支えられています。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/11cbbb7e-29d4-f29f-9c70-7ac41e0f75d9.png)

POSIX に準拠してアプリケーションを開発すると移植性が高まるという話はよく知られていますが POSIX に準拠するという事が本当はどういう意味なのかは案外知られていない気がします。POSIX は C 言語用の POSIX API やシェルスクリプト用の POSIX コマンドを標準化していますが、**POSIX 準拠とは「POSIX API や POSIX コマンドだけを使って C 言語とシェルスクリプトで作ること」ではありません**。それだと多く OS が準拠しているはずの POSIX なのに、その上で動作するアプリケーションを他の言語では作れないという意味不明な話になってしまいます。また開発言語が（現代の基準で生産性の低い）C 言語と（機能不足で遅い）シェルスクリプトに限定されるとしたら、新しい言語や多くのライブラリを否定する標準規格となってしまい誰も従いません。POSIX とは使用してよいライブラリやコマンドを制限するものではりません。将来の拡張と自由を保証しており「**新しいことは POSIX 外で行う**」事が前提の標準規格です。POSIX 自体の仕様はほとんど変化しませんが、それは新しいものを作り出す標準規格ではなく POSIX が標準化された 1988 年当時の Unix を起点として、どの Unix 系 OS にも共通する「OS のインターフェースだけ」を標準化するものだからです。ある OS の新機能は共通するものでなければ POSIX に組み込まれませんが、別の OS が共通する機能を開発することはあまりありません。安定していると言えば聞こえは良いですが **POSIX の規格は昔の OS の仕様のままほとんど改善されず最低限の共通機能しか標準化されていない**ということです。POSIX は OS のインターフェースのみを対象としたものであるため、ソフトウェア開発の生産性を上げる優れた言語やコマンドやライブラリやミドルウェアが含まれることはありません。だからと言って **POSIX 外のソフトウェアを使用すると移植性が下がるとは POSIX は言っていない**のです。POSIX で規定された機能だけを使って開発するのは現実的ではありませんし、そもそも POSIX も POSIX で規定した機能だけを使えとは言っていません。POSIX が規定するのはあくまで OS の基盤あって、ソフトウェア開発の基盤は POSIX の対象外、標準化が必要なら別の団体でやりましょうというだけです。

また POSIX で標準化されていないインターフェース（例えば GPU や仮想化・コンテナ技術など）を使っていても POSIX 準拠と呼ぶこともできます。なぜそう言い切れるのかと言うと POSIX のドキュメントに「**拡張機能を利用する POSIX 準拠アプリケーション」という定義がある**からです。拡張機能とは POSIX で規定されていない OS のインターフェースのことで、具体的には GNU や BSD 固有の API（システムコールやライブラリ）や POSIX コマンド以外の OS のコマンド等のことです。拡張機能を利用する POSIX 準拠アプリケーションという定義があることから、POSIX で規定されてるものだけを使うというのが間違いであることがはっきりと分かります。POSIX の目的は移植性が高いアプリケーションの開発を容易にすることです。逆に言えば、新しい言語やコマンド、ライブラリやフレームワーク、GUI やデータベースなどは POSIX の目的ではありません。それらは POSIX の対象範囲ではないため POSIX で標準化されることはありませんが、だからと言って POSIX は拡張機能を使ってはいけないとは一言も言っていません。**POSIX で標準化された OS の機能だけを使い、残りすべてを自分で作成しなければならないとしたら、ソフトウェア開発の生産性は大きく下がってしまい開発コストは大きく膨れ上がってしまいます**。POSIX で規定したものだけを使うことが「POSIX 準拠」なのではなく POSIX で規定した部分が POSIX に従っていれば「POSIX 準拠」です。拡張機能の使用は自己責任というだけで POSIX は使用を禁止してはおらず「POSIX 準拠ではないなら移植性はない！そんな物を使うと移植できなくて後悔するぞ！」などと責め立てることはないのです。

POSIX の目的である移植性とはアプリケーションを他の環境でビルドしやすくすることです。追加のコマンドをインストールしやすくするものであって、POSIX コマンド以外をインストールしないようにしようというものではありません。POSIX コマンドはどこでも使えるかもしれませんが **POSIX コマンド以外もどこでも動く**という事実は重要です。POSIX コマンド以外の移植性を実現したのが POSIX の成果だからです。オープンソースのソフトウェアに限れば使えなくなったソフトウェアはまずありませんし将来使えなくなるかもなんて心配する必要もありません。ソースコードが公開されているなら自分で後を引き継ぐことができるからです。昔の仕様である　POSIX コマンドよりも最新のコマンドの方が高機能で便利で優れています。**「どの環境でも動く（POSIX コマンド以外の）POSIX 準拠コマンド」を使えば良いので、移植性を理由に機能が貧弱でできることが少ない POSIX コマンドに固執する意味はありません**。移植性にとって重要なのは POSIX 準拠という言葉ではなく実際に移植されていることです。そもそも POSIX コマンドだからといってシステムに最初からインストールされているとは限りません。**POSIX の要件に「POSIX コマンドは最小構成でインストールしなければならない」という規定はありません**。どちらにしろ何かをインストールしなければシステムが動かないのであれば便利なコマンドをインストールして使うのもの同じことです。**パッケージ管理システムの登場で今のインストール作業はとても簡単になりました**。よく使われているソフトウェアであればインストールでビルド作業を行う必要はありません。CLI コマンドなら多くの場合は設定作業も不要です。なんでも自作するのではなく**本当に価値があるものを作る**という考え方が重要です。いくら動いたって「求めている機能」を実現できなければ価値はありません。時間をかけて作っても使われなければただの無駄な開発コストです。

**シェルスクリプトには環境依存が激しい**という問題があります。これは POSIX コマンドあっても動作が各環境で完全な互換性がないからです。POSIX で標準化されている範囲のシェルの文法やコマンドやオプションであっても互換性は完全ではありません。POSIXで規定されている仕様に従っているものでも動作に違いがあるのです。また現実には **POSIX に準拠していない実装やバグで POSIX で決まっている通りに動かないこともあり、POSIX の範囲なら OS を変更したり更新したりしても動作が変わらないという保証はありません**。POSIX の仕様は統一した動作に決まっているわけではないので OS を更新するために環境依存問題と戦い続ける必要があります。POSIX は所詮仕様という文書に過ぎないので仕様が変わらなくても実際の動きは変わります。「POSIX には仕様が明確に決められてないところがあります」のような説明を見かけますが、この説明は間違っており、POSIX が仕様を明確に決めてないのではなく、各 Unix で動作が異なっているため「**POSIX は 各 Unix で仕様が異なる部分を明確に指摘している**」というのが正しい説明です。各 OS で動作が違っている所を統一した動作に規定してしまうと互換性が保てなくなるので変更できないのです。例えばコマンド出力の位置揃えのための空白の数は（POSIX で規定するのを忘れていたのではなく）各 OS でバラバラであると "POSIX は指摘" しています（参考 [POSIXコマンド出力のインデント・カラム間の「空白の数が環境によって異なるのはPOSIXに準拠した動作」であるという話](https://qiita.com/ko1nksm/items/0d50ca13025120d78188)）。このようなものは POSIX が詳細な仕様を規定しなかったから各 OS ベンダーが仕方なくバラバラに実装したのではなく、先に OS ベンダーがバラバラに実装しており、その事実を POSIX は標準化しているのです。POSIX に「動作が決まっていない」と書いてあるならば、それは理由があって意図的にそう書いたのです。もし本当に POSIX が仕様を決めるのを見逃していたのであれば何も書いていないはずです。実際の所 POSIX にも書き漏れはあるのですが数はそんなに多くはありません。これらのミスは何年毎の POSIX の改定で修正されています。**シェルスクリプトが依存しているコマンドの多さ**がシェルスクリプトの環境依存が激しい原因の一つです。**POSIX コマンドは多くの OS でそれぞれ独自に実装されている場合が多く、実装の種類の多さが環境依存の問題を悪化させています**。もし一つの団体が「POSIX コマンド」を作っていたとしたら、移植性の問題は起きなかったでしょうが、残念ながら歴史的事情でそういうことにはなりませんでした。

POSIX ではそれぞれの OS には動作に違いがあることがで明らかにされています。高い移植性の実現には「各 OS の動作の違いに対応してアプリケーションを書く」ことが重要になってきますが、POSIX には各 OS の仕様の詳細は記載されていません。POSIX だけを参照してアプリケーションを書いても動くかどうかは運次第です。各 OS のドキュメントをしっかり読んで、各 OS で動作テストをしなければ、どこでも動くアプリケーションを開発することはできません。だから **移植性が高いアプリケーションを書くのは本来は大変な作業**なのです。こういった大変な作業を楽にするために、各言語やライブラリは各 OS の動作の違いを吸収して普通にアプリケーションを書くだけで移植できるようになっています。つまり「**他の言語では POSIX に準拠する作業は言語開発者やライブラリ開発者がすでに行っている**」ということです。そういったサポートなしに POSIX で標準化された API や コマンドだけを使ってどの環境でも動くアプリケーションを開発しようとしたら各 OS の多くの違いに悩まされることになります。**「POSIX 準拠を気にしないで開発できる他の言語の方が簡単に楽に高い移植性を実現できる」 というのは皮肉な事実**ですが、POSIX が最初に標準化された 1988 年から、それだけソフトウェア開発の世界は大きく発展したということです。**今や誰でも意識せずに POSIX 準拠アプリケーションを作っています**。実際に開発したアプリケーションはどの環境でも動くでしょう？ 便利な言語やライブラリを使って「何も考えずに移植性が実現できるのなら」やる価値はありますが、各 OS の違いに悩まされながら開発するほど移植性の価値は高くありません。移植されることがないのに移植性を気にするよりも、もっと重要なことが他にあるはずです。

**補足** この記事は POSIX のドキュメントの文章に基づいて書いています。具体的にどこに書いてあるのかを知りたい人はこの記事の[後半](#posix-の定義を自分の目で確かめてみよう)を参照してください。この記事の内容は POSIX の C 言語とシェスクリプトの両方の開発に当てはまる話ですが、私が普段やっていることがシェルスクリプト分野であるため、シェスクリプトの話に偏っています。ご了承ください。

## 「POSIX 準拠」の正しい理解

ここでは POSIX はどういうものかを振り返りながら「POSIX で規定されているものだけを使ってアプリケーションを開発する」という理解が間違っている理由を解説します。これを読めばその理解が間違っているどころか、POSIX の考えや目的とは正反対の理解であることがわかると思います。

![no.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/7cf3253c-0bb1-6916-59ce-be0a8c5403e9.png)

### 「POSIX 準拠」の定義

POSIX とは OS ベンダーとアプリケーション開発者の両方が参照すべきドキュメントです。そのため POSIX 準拠の要件にも「OS ベンダー向け」と「アプリケーション開発者向け」の二つの要件が定義されています。これらが定義されている場所は [2. Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html) です。

OS ベンダー向けの POSIX 準拠の定義は大きく二種類ありますが、ほとんどの人は OS ベンダーではなくアプリケーション開発者であるため、OS ベンダー向けの話は省略します。

アプリケーション開発者向けの POSIX 準拠の定義は大きく五種類ありますが、その中で私が考える二つの大きな定義は「厳密な POSIX 準拠アプリケーション」と「拡張機能を利用する POSIX 準拠アプリケーション」です。以下はこの二つの違いを示したものです。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/88433168-4396-30e2-fa70-cc99112ce7af.png)

### OS とアプリケーションの区別

簡単なようで意外と難しいのが OS とアプリケーションの区別です。POSIX は OS のインターフェースを定義しているため、そのインターフェースを実装しているのは OS であると言えます。しかし POSIX が定義しているのは「**移植性がある** OS のインターフェース」だけなので、POSIX が定義しているものが OS の全てでは有りません。「移植性がない OS のインターフェース」が残っています。

![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/6812c660-ef55-7eb8-90a6-d98703f70805.png)

区別するのが難しい理由はパッケージ管理システムが登場したからです。実はパッケージ管理システムが登場したのは POSIX 策定の後で Linux (Debian?)が最初です（参考 [wikipedia: Package Manager](https://en.wikipedia.org/wiki/Package_manager#Impact) 及び [How package management changed everything](https://web.archive.org/web/20090223072201/http://ianmurdock.com/2007/07/21/how-package-management-changed-everything/)）。それまでは OS と言えば OS ベンダーがリリースしたものに含まれているソフトウェアであったため区別するのは比較的簡単でした。Windows や macOS は今でもそれに近い状態です。しかし Linux 等ではパッケージ管理システムによって膨大なソフトウェアを利用することが出来ます。

Linux ディストリビューションにおいて**広義の OS は OS 標準のパッケージ管理システムでインストールできるソフトウェアすべて**です。その中には Python 等のプログラミング言語や Office ソフトやゲームまで含まれています。しかし多くの人はこのようなソフトウェアは、パッケージ管理システムに収録されているだけで OS の一部とは考えていないのではないでしょうか？実際にパッケージ管理システムを使わずに Python や Office ソフトをインストールした場合 OS の一部とする理由はなにもありません。

したがって OS の厳密な定義はできませんが、一般的な感覚として以下に該当するソフトウェアは OS の一部であると私は考えています。重要な点としてソフトウェアの種類で OS かどうかの判断はしていません。（プログラミング言語 = OS とは限らないということ）

- POSIX で規定されているものは OS
- Unix で昔から OS の一部として配布されていたソフトウェアは OS
- OS の最小構成でもインストールされているソフトウェアは OS
- OS 自身やユーザーを管理するためのソフトウェアは OS
- GUI のウインドウシステムや GPU 周りは OS

**POSIX 準拠のアプリケーションは上記以外のプログラミング言語、コマンド、ライブラリ、データベース、ウェブサーバー、ミドルウェアなどすべて**です。POSIX の定義には OS とアプリケーションの区別しか無いため、OS 以外はすべてアプリケーションとして考えます。

### 開発言語は C 言語とシェルスクリプトに限定されない

**そもそも POSIX は OS のインターフェースしか定義してないんだから
どの言語で実装したって良いんです！**

前項で OS と アプリケーションの区別の話をしたのは、例えば Python を使ってアプリケーションを開発した場合でも POSIX 準拠の定義を満たすという話をしたかったからです。

例えば Python という言語は POSIX では規定された言語ではありませんが、その理由は **Python が OS のインターフェースではない**からです（下記補足参照）。Python は POSIX の定義上はアプリケーションに分類されます。従って Python 及び Python で開発したアプリケーションが内部で POSIX で規定された POSIX API のみを使用しているということが前提となりますが、**Python で作られたアプリケーションは「厳密な POSIX 準拠アプリケーション」の要件を満たす**といえます。

そうでなければ C 言語を使って開発した「独自コマンドはPOSIX で規定されていないコマンド」なので、自分で作ったコマンドを使った時点で「厳密な POSIX 準拠アプリケーション」ではなくなるという意味不明な結論になってしまいます。独自開発のコマンドだろうが他人が作ったコマンドだろうが言語だろうがライブラリだろうが、それらに大きな違いはありません。OS のインターフェースではないものをいくら使おうが OS のインターフェースを定めた POSIX とは何も関係のない話なのです。

まとめるとこういうことです。

- 各プログラミング言語およびライブラリ
  - 内部で OS のインターフェースを呼び出さないもの<br>→ OS のインタフェースではないものは自由に使える（POSIX 準拠）
  - 内部で POSIX で規定された OS のインターフェースを呼び出すもの<br>→ 厳密な POSIX 準拠
  - 内部で POSIX で規定されていない OS のインターフェースを呼び出すもの<br>→ 拡張機能の利用（各 OS に対応している限り POSIX 準拠）

でもまあこんな長々と説明しなくても一言で済みます。**POSIX のどこを見ても「POSIX 準拠にするためには C 言語とシェルスクリプトだけで作らねばならない」とは書いていません**。禁止されてないのであれば何を使ってもいいのは自明です。

**補足** 仮に自分が新しいプログラミング言語を作ったとして、それが OS 標準のパッケージ管理システムから利用可能になっただけで、自分が作った言語が OS のインターフェースになったと思う人はいないでしょう？ もしシステム全体で Python を使うことを前提として開発された OS だった場合は、Python が OS のインターフェースと言えるかもしれませんが。

### シェルスクリプトの移植性と開発効率は低い

ガンカーズが UNIX 哲学として「梃子の効果と移植性を高めるためにシェルスクリプトを利用せよ」と言ったせいで「移植性が一番高いのはシェルスクリプト」と勘違いしている人を時々見かけますが、これは明らかに間違いです。ガンカーズが言った言葉の意味は他のアーキテクチャのコンピュータに UNIX を移植開発する場合の話で、他の OS へアプリケーションを移植する場合の話ではありません。しかも 1980 年代の UNIX 開発の話というかなり古いものです。

現代では**シェルスクリプトでなくとも移植性は高い**ですし、なんなら他の言語の方が移植性は大幅に高いです。その理由はシェルスクリプトが OS 毎に動作が微妙に異なる POSIX コマンド（UNIX コマンド）に依存していることが多いのに対して、他の言語では OS 毎の微妙な動作の違いを吸収しているからです。残念ながら現代の基準で言えば**シェルスクリプトに移植性が高いというメリットはありません**。

POSIX の C 言語インターフェースに比べると、POSIX シェルおよび POSIX コマンドの移植性は低いのが現状です。UNIX コマンドは各 UNIX でそれぞれ拡張されてきたため、もともと互換性が低いのです。その互換性が低い中でかろうじて移植性がある部分をまとめたのが POSIX です。したがって機能も少なく POSIX シェルと POSIX コマンドだけを使って開発することは、開発効率も低いということを意味しています。

また POSIX の C 言語インターフェースの互換性も完璧ではありません。したがって多くの言語は OS の細かい違いを吸収しながら言語やライブラリを開発しています。C 言語であっても、POSIX API を直接使用するよりも移植性を考慮して作られたライブラリを使うほうが移植性は高くなりますし、その方が開発効率が高いです。他のプログラミング言語ならなおさらです。

前項で説明したように、POSIX に準拠する条件は、C 言語かシェルスクリプトを使うことではありません。POSIX コマンドだけを使うことでもありません。OS のインターフェースを使用するときに**間接的であっても** POSIX で規定されたインターフェースを適切に呼び出していれば、それで POSIX 準拠になります。

補足ですが、ガンカーズの UNIX 哲学は、いくつかの UNIX 哲学の中でも特に問題が多い UNIX 哲学です。詳しくは[[名著「UNIXという考え方 - UNIX哲学」は本当に名著なのか？ 〜 著者のガンカーズは何者なのかとことん調べてみた](https://qiita.com/ko1nksm/items/f1800c6ff6dd649d7429)」を参照してください。

### POSIXはシェルスクリプトで問題になるOSの違いを吸収できていない

シェルスクリプトの移植性が低い原因は、結局のところ OS に標準インストールされているコマンド、特に POSIX コマンドを使っているからです。POSIX コマンドはいろんな OS ベンダーがそれぞれ開発しており、実装がたくさんあります。実装がたくさんある = それぞれで動きが違う = 移植性が低くなるということです。POSIX は移植性を高めるための標準規格だから、そこで定義されている POSIX コマンドを使えば移植性が高くなるはず・・・これが間違った考え方なのです。

POSIX コマンドはいろんな OS ベンダーが開発しており移植性が低いという問題があるから、それをどうにか解決するために作られたのが POSIX です。シェルスクリプトの移植性を高めるための方法が POSIX 文書に書いてあり、それを注意深く読んでシェルスクリプトを書くことが、シェルスクリプトの移植性を高めるために必要なことです。そしてそれが POSIX コマンドを使うことの大変なところです。

ハードウェアの違いを吸収しているのは OS （カーネルやドライバ）です。そのおかげでどの言語で作ったソフトウェアであっても異なるハードウェア上で動きます。しかし OS にも違いがあります。OS の違いは誰が吸収すればよいのでしょうか？ POSIX コマンドは OS の一部とみなされているコマンドです。シェルスクリプトにとっての OS の違いは誰が吸収すればよいのでしょうか？

つまり「OS の違いを吸収する層」が必要なのです。一般的なプログラミング言語であれば、それは言語機能そのものやライブラリです。シェルスクリプトにとっては（OS 一部である POSIX コマンドではなく）新たに作られたコマンドです。新しく作られた多くのコマンドは特定の OS に依存しておらずどの環境でも動きます。OS に違いがあるということは **OS の機能を直接使わないことが移植性を高めるための重要な鍵**になります。どの環境でも全く同じように動くコマンドだけを使っているシェルスクリプトの移植性が高いのは道理です。もちろんコマンドだけではなくシェル自体も移植性が高い（どの OS にでも移植されていて動く）シェル、例えば bash などを使う必要があります。

### 「厳密な POSIX 準拠アプリケーション」の定義

「厳密な POSIX 準拠アプリケーション」とは OS インターフェースとして POSIX で規定されたものだけを使用するアプリケーションのことです。OS のインターフェースでないもの（= アプリケーション）の利用に関しては特に制限は書いてありません。

### 「拡張機能を利用する POSIX 準拠アプリケーション」の定義

「拡張機能を利用する POSIX 準拠アプリケーション」とは POSIX で規定された OS のインターフェースを使い、さらに **OS の拡張機能**を利用するアプリケーションのことです。OS のインターフェースでないもの（= アプリケーション）の利用に関しては特に制限は書いてありません。

OS の拡張機能は以下のものを意味しています。「OS」の拡張機能なのでアプリケーションの領域は含まれていないことに注意してください。拡張機能の定義は [2.1.1 Requirements](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_01) に書かれています。

- 追加の関数
- 追加のヘッダファイル
- 標準ヘッダファイルの追加のシンボル
- 追加のユーティリティ（コマンド）
- 標準ユーティリティの追加のオプション
- 追加の環境変数
- 追加のファイルタイプ
- 準拠していないファイルシステム（大文字と小文字を区別しないファイルシステムやネットワークファイルシステム等）
- 動的に作られるファイルシステム (`/proc` 等)
- 追加の特殊ファイル (`/dev/stdin`, `/dev/stdout`, `/dev/stderr`)

これらのリストの上に書いてある **but are not limited to** という言葉が意味する通り、拡張機能はこれだけに限定されません。つまりなんでもあります。この定義から拡張機能を使ったとしても POSIX 準拠の定義を満たすということはっきりと示されています。

### POSIX の成果とは何だったか？

そもそも POSIX の目的とは何だったでしょうか？そうです。移植性が高いアプリケーションの開発を支援するのが目的です。そして POSIX の成果によって多くのどこでも動くアプリケーションが誕生しました。

さて、それらのアプリケーションを使ったら POSIX 準拠ではないと POSIX 自身が言ってるとしたらおかしな話だと思いませんか？

![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/7ef54966-46d8-e1b1-57bc-7f44f11dc578.png)


「POSIX で規定されているものだけを使ってアプリケーションを開発すること」が間違いなのは、冷静に考えればわかることだと思います。POSIX の成果で生まれた多くのアプリケーションを POSIX が使うなと言っているとしたら、なんのための POSIX なんだ？となるでしょう。つまりそれは謎マナー講師が勝手に作った嘘マナーということです。

### 論理的に考えてみよう

POSIX 準拠というのが「C 言語やシェルスクリプトを使い、POSIX API や POSIX コマンドだけを使うこと」ではないことは、論理的に考えても同じ結論にたどり着くはずです。例えば POSIX で標準化されていない `which` コマンドの話で考えてみましょう。

1. `which` コマンドは POSIX で標準化されていません。
2. `which` コマンドと同等の機能の `my_which` コマンドを POSIX に準拠して C 言語で自分で作ります。
3. しかし作った `my_which` コマンドは POSIX で標準化されていないコマンドなので使ってはいけないことになります。

POSIX コマンド以外を使ってはいけないという理屈だと、自分で作ったコマンドでさえ使えないということになってしまいます。明らかにおかしいですよね？

ここで「自分で作ったものであれば OK」という例外規則を思いつくかもしれませんが、しかし開発メンバーが作ったコマンドはどうなるのかという疑問が生まれるはずです。

1. 自分で作ったものであれば OK
2. 開発チームのメンバーが作ったものは？
3. 開発チーム以外のメンバーが作ったものは？
4. 社外の人が作った場合は？

もし私が本物の `which` コマンドを作ったオープンソースプログラマだったとしましょう。それなら自分で作ったものを使うのは OK ですよね？では私の開発チームメンバーは私が開発した `which` コマンドを使っていいのでしょうか？ ダメな場合それぞれが自分で `which` コマンドを作らなければいけないということになります。明らかに無駄な作業です。`which` コマンド程度ならまだ簡単ですが JSON を解析するために、各自で `jq` コマンド相当のもの作るなんて馬鹿げています。私が開発した `which` コマンドは私のチームメンバー以外も使えると便利でしょう。社外の人だって使えれば便利でしょう？それがコマンドを再利用するということです。

もちろんこの話は `which` コマンドだけではなくすべてのコマンドに当てはまります。例えば動画や音声を変換する `ffmpeg` というコマンドがありますが、このような難易度が高く開発に時間がかかるようなものをそれを各自で作るなんてまず無理なわけで現実的な話としてインストールして使うしかありません。そうでなければ「自分で `ffmpeg` を一から作れないから私には動画変換はできません」と言うしかありません。他の人がライブラリやコマンドを使って楽々開発しているものを、自分で `ffmpeg` を作れないから無理と言うのであればプロジェクトから外されるでしょう。

ライブラリやコマンドの開発はとても大変で時間がかかるものです。たった数十行程度で出来るようなものばかりではありません。大きなものでは数千行〜数万行以上にもなり開発に時間がかかるものであるため、他の人が作ったものを使うのが普通です。そして自分で作るのではなく他人が作ったものを使うというだけで、アプリケーションが POSIX 準拠でなくなるとしたらはおかしな話です。ソフトウェアの中身が同じなのに開発した人が違うというだけで POSIX 準拠かどうかというソフトウェアの性質が変わるなんてありえません。

### OS のインターフェースさえ標準化されていれば移植性は実現できる

POSIX が標準化したのは「OS のインターフェースだけ」です。別の OS で異なっている所は OS 部分しかないはずなので、OS のインターフェースさえ同じであれば、アプリケーションはどこでも動くはずです。

![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/9e0db1f6-82d0-ad66-5d11-a433dd6610c2.png)

POSIX の標準化の対象はあくまで OS のインターフェース部分なので、それ以外（例えば他の言語やデータベース等）は POSIX の標準化の対象外となっています。したがってそれらが POSIX で標準化されていないのは当たり前のことです。別に移植性が低かったから「POSIX に認められなかった」とかそういう話では有りません。そもそも移植性が低いという問題を解決するのが POSIX の仕事だったはずです。

### POSIX 準拠とは「POSIX が定めた要件に従う」こと

POSIX 準拠とは POSIX が定めた要件に従うことだけです。POSIX が定めていない部分に関しては使用を禁止してはいないのですから、どう使おうが自由です。「要件に従う」は「要件にないものは使うな」という意味にはなりません。

POSIX は OS のインターフェースを標準化していますが、GUI のような OS のインターフェースと言えるようなものでも POSIX で標準化されていないものがあります。これは歴史的な事情で POSIX 策定時に、すべての OS で同じように動くものがなかったからです。だからといって POSIX はそれらを使うなとは言っていません。

![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/9f2b4c2a-0f6a-c4a9-cd41-3bbd3f9db1cc.png)

### POSIX が定めた要件とは「実装定義」と「未規定」に対応すること

（OS 実装者向けの要件は省略するとして）アプリケーションを多くの環境で動くようにするには、アプリケーション開発者は一体何をすればいいでしょうか？このアプリケーション開発者がやらければいけないことが「POSIX が定めた要件」です。特に重要なものを以下に紹介します。

1. 実装定義 (implementation-defined) または未規定 (unspecified) は実装ごとに動作が異なるので、実際の実装の動作のすべてに対応すること
2. 未定義 (undefined) となっているものは使用してはいけません
3. 廃止 (obsolescent) とされたものは使用してはいけません

特に重要なのが 1 です。POSIX では実装定義や未規定となっている部分があります。これは実際の実装（Linux や macOS）よって動作が異なっているものです。しかし POSIX に実際の実装の動作は書いてありません。それは **POSIX だけを参照してもどこでも動くアプリケーションを開発することは不可能**であるということを意味します。つまり POSIX を参照して、実装定義または未規定となっている部分を確認し **「実際の実装の動作に対応しなければいけません」** ということを POSIX はアプリケーション開発者がやらなければいけない要件として定めています。

未規定が使用禁止となってないことも重要です。例えばシェルの `local` コマンド（bash 依存。bash 以外でも使えますが）を実行した結果は未規定となっています（[Command Search and Execution](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01) 参照）。未規定は未定義や廃止のように使用禁止にはなっていません。つまり `local` コマンドは POSIX で使用を認めらている拡張機能です。ただこれらを使った場合に動作に対応すればよいだけです。対応というのは `local` コマンドをすべてのシェルでローカル変数を定義するための機能として使うという意味ではなく（そもそも POSIX にはローカル変数を定義するためのものとは定義されていない）例えば「このシェルでは対応していません」のようなエラーメッセージを出して終了するだけでも十分です。ただしアプリケーションのドキュメントに `local` コマンドを使っているから対応しているシェルでしか動かないと明記する必要はあります。**`local` コマンドを使うシェルスクリプトは POSIX に準拠してないのではなく「拡張機能を利用する POSIX 準拠アプリケーション」** なのです。

### 「実装定義」と「未定義」と「未規定」の違い

#### 実装定義 (implementatdion-defined)

[implementatdion-defined](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_02)

実装者が仕様を決めなければいけないとされているものです。未規定との違いは**実装者に実際の動作を文書化することを義務づけている**所です。実装者が仕様を決めないといけないのは、この機能をアプリケーション開発者が使えるようにするためです。従って実装定義となっている機能はアプリケーションから使用して構いません。

#### 未定義 (undefined)

[undefined](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_07)

不正な使い方をした時の結果を説明する時の用語です。そもそも間違った使い方であり、そのような使い方をしてはいけないため、結果が規定されていなくても不都合はありません。未定義とされている機能はアプリケーションから使用してはいけません。

#### 未規定 (unspecified)

[unspecified](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_08)

正しい使い方をした時の結果を説明する時の用語です。使い方自体は正しいため未規定とされている機能を使っても良いのですがその結果は POSIX では決められていません。正確には実際の実装がバラバラで統一されていなかっため POSIX で規定することが出来なかったと言うべきものです。

実装定義と似ていますがこれは主に**拡張機能の実装を可能にする時に使われる用語**で、拡張機能を実装しないならば実際の動作を文書化する必要がないという点が異なります。例えばシェルの配列の構文（例 `ary=(1 2 3)`）は、配列に対応していないシェルではその仕様を文書化することは不可能です。対応してない未知の構文に対してどういう定義ができるというのでしょうか？という話です。

### POSIX 準拠とはすべての環境で動くことではない

`local` コマンドを使ったシェルスクリプトは純粋な POSIX シェルでは動作しません。しかしそれは POSIX 準拠の話とは別の話です。

まず大きな二つの POSIX 準拠の基準がありました。

1. 厳密な POSIX 準拠アプリケーション
2. 拡張機能を利用する POSIX 準拠アプリケーション

1 に関しては拡張機能を使わないのですから、ほぼすべての環境で動くことを目指したものです（それでも未知の環境に対応するのは不可能です）。しかし 2 に関しては拡張機能を使った POSIX 準拠アプリケーションが拡張機能がない環境で動かないのは自明です。

すなわち POSIX 準拠アプリケーションに「すべての POSIX 準拠の環境で動かなければいけない」という要件は有りません。POSIX はアプリケーションの移植性を高くするための標準規格ですが、完璧な移植性を実現しなければいけないという要件は有りませんし、完璧な移植性を保証してくれるわけでも有りません。移植性を高くするだけです。

動作に前提条件がある POSIX 準拠のアプリケーションがあったってよいのです。`local` コマンドを使ったシェルスクリプトは、拡張機能に対応した POSIX 準拠シェルを備えた環境という条件を満たせば動きます。

### POSIX 準拠してもすべての環境で動くわけではない

POSIX 準拠アプリケーションが満たさなければいけない要件の一つに、未規定 (unspecified) になっている部分に対して実際の動作に対応しなければいけないという要件があります。

具体的な例でいうと `echo -n` の `-n` の意味は未規定です。重要なのは未規定ということは `-n` に対してどのような意味をもたせてもいいということです。ほとんどのシェルでは改行しないといういう意味か `-n` という文字列ですが POSIX の定義上はどのような実装をしても良いとされています。これは拡張性を持たせるためにあえてそうしています。

そうなると `-n` が実際にどういう意味であるかは、実際のシェルや OS を調べてみなければ知ることは不可能ということです。もし POSIX に準拠して作ったアプリケーションが他の環境でそのまま動いたとしても、それは**たまたま動いた**というだけです。運良く互換性がある実装だったに過ぎません。たまたま動いた例があったとしても「POSIX 準拠して開発すればすべての環境で動くんだ」という仮説を証明したことにはなりません。

POSIX 準拠してアプリケーションを書いたとしても、すべての環境で動く保証はありませんから、動く保証をするためには**実際の環境でテストをしなければいけない**とうことです。どこでも動くソフトウェアを主張するならば、せめてテストコードを使ったテストの自動化を行うことは必要です。第三者がテストできないものを提示して、すべての環境で動くんだと主張した所で、信用できないでしょう？

### 逆に「POSIX に準拠していないアプリケーション」とはなんなのか？

拡張機能を使っても POSIX 準拠だというのなら、すべてが POSIX 準拠とならないか？そんなのおかしい、この説は間違っていると考える人へ解説すると、「POSIX に準拠していないアプリケーション」とは POSIX が定義した要件に反しているアプリケーションのことです。

例えば `date` コマンドは現在の日付を標準出力に出力するコマンドですが、Windows の `date` コマンドのように新しい日付を設定するコマンド（オプション無しで実行した場合）として実装したら、それは POSIX 準拠してないことになります。しかしこれは OS 実装者側の話です。

POSIX に準拠した OS 実装上で、POSIX に準拠していないアプリケーションは基本的に動きません。だから動作するアプリケーションは POSIX 準拠と言えるのはある意味事実です。しかしそれでも POSIX に準拠していなアプリケーションはあります。例えば POSIX のアプリケーションが満たすべき要件として未定義や廃止といった機能は使ってはならないとされているので、これらを使うアプリケーションは POSIX 準拠ではないと言えます。

もう一つの POSIX 準拠のアプリケーションに要求されている重要な要件は「実装依存」や「未規定」の動作に対応することです。これらは実装ごとに動作がバラバラです。こういったものを例えば Linux (GNU) など**特定の実装にしか対応していない場合**は POSIX 準拠ではないということになります。未規定の機能を使うということは拡張機能を使うということです。拡張機能を使うことは POSIX で禁止されていませんが、実装依存の機能や拡張機能を使う以上、その実装の動作に対応しなければどこでも動かなくなってしまう（POSIX 準拠ではない）ということです。

また GNU 版の `df` コマンドは以下のように ブロック数 を 1 KB 単位で表示します。実はこの動作は POSIX に準拠していません。POSIX 準拠の動作は 512 B 単位です。

```sh
$ df
Filesystem            1K-blocks     Used Available Use% Mounted on
udev                   15869788        0  15869788   0% /dev
tmpfs                   3179864     3296   3176568   1% /run
 :
```

POSIX に準拠していない動作**のみ**に対応しているアプリケーションは POSIX 準拠ではないと言えるでしょう。

しかし GNU 版の `df` は環境変数 `POSIXLY_CORRECT` を定義すると POSIX 準拠の動作に変更することが出来ます。このようにデフォルト環境では POSIX に準拠していなくても、設定で POSIX 準拠の動作になるのであれば（POSIX 準拠環境では）POSIX の要件を満たすといえます。アプリケーション側も 1 KB 単位と 512 B 単位の両方に対応していれば POSIX 準拠と言えます。

要約すると「POSIX に準拠してないアプリケーション」というのは POSIX の規定している内容と矛盾しているアプリケーションのことです。POSIX で規定されてないもの（拡張機能）に関してはどれだけ使っても構いません。ざっくり言えば、どんな機能を使おうがどこでも動くようにしたら POSIX 準拠です。

### POSIX は OS 間の完全な互換性の実現を目指したものではない

POSIX には「実装定義」や「未規定」の部分が多く存在します。これはそれまで開発されたアプリケーションを修正することなく動かすため（後方互換性を実現するため）に必要なことです。

元々 Unix は AT&T が開発したオリジナルの Unix をそれぞれの OS ベンダーが改良したものであるため、インターフェースは非常に似ていました（下の左の図）。しかし各自バラバラに改良を加えていたため、時がたつにつれてインタフェースに細かい違いが生まれてきました。

異なる OS 間でのアプリケーションの移植性に問題がでるようになったため、OS のインターフェースを標準化する必要性が生まれました。それを実現したのが POSIX です。**注意** Unix の仕様を元に POSIX が作られています。POSIX の仕様を元に Unix が作られたわけではないので勘違いしないようにしてください。

しかし POSIX によって OS のインターフェースを完全に同じものへと統一してしまうと、それまで開発されていたアプリケーションが動かなくなってしまいます（下の右の図）。アプリケーションの移植性を高くするのが目的のために、それまでのアプリケーションが動かなくなってしまうようでは本末転倒です。

![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/17aabf11-c9a3-1531-963f-a3f2b8112122.png)

そこで POSIX が取ったアプローチでは OS によって動作が異なる部分を「実装定義」や「未規定」という形で標準化することで、どのように実装しても POSIX 準拠 OS の条件を満たすとしました（下の左の図）。

これにより、それまでの POSIX に準拠していないアプリケーションは新しく POSIX に準拠した後継 OS でそのまま動くことになり、後方互換性が実現されます。そして POSIX に準拠したアプリケーションは、**OS によって動作が異なる部分に対応する**という要件を満たすことで POSIX に準拠した OS での移植性を実現することが出来ます（下の右の図）。

![image8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/78c249a3-2377-618a-049f-24f6ae33be04.png)

「POSIX 準拠」というのは**OS 実装側だけではなくアプリケーション開発側も要件を満たして初めて意味がある**ものです。

### POSIX は Java の「Write once run anywhere」とは性質が全く異なる

POSIX は アプリケーションの移植性を高めるための標準規格ですが、OS 間での完全な互換性を実現したものでは有りません。

Java には「Write once run anywhere」、一度プログラムを書けば、どこでも実行できるというスローガンが有りました。これが完全に実現されていないのはよく知られた事実ですが、それでも単一のソースコードでどこでも実行できることを目指したものです。OS 間の互換性問題を Java が解決してくれるためプログラマは OS の違いを意識する必要がありません。

しかし POSIX はそうではありません。元々 OS 間には違いがあるという前提なので OS 間の互換性問題を意識せずにどこでも動くものではなく、**プログラマが OS 間での互換性問題を意識して自分で解決する**ことで、はじめてどこでも動くようになるのです。

また、どこでも動くと言っても未知の OS で「実装定義」や「未規定」がどのように実装されているかを知ることは出来ないため、POSIX に準拠して書いた所で未知の OS で動くかどうかはわかりません。実際の環境で動作テストしてみなければわからず、動作テストする方法がなければ動くことを証明することは出来ません。

POSIX によって実現されるアプリケーションの移植性というのは「OS が POSIX に準拠してる」から、何も考えずにどこでも動くのではなく「OS と アプリケーションの両方が POSIX に準拠する」ことで実現されるのです。我々**アプリケーション開発者にも移植性問題に対応するという要件が課せられている**ということを忘れてはいけません。POSIX に準拠してソフトウェアを開発するというのは面倒くさい作業なのです。

### ライブラリ・コマンドを使うことで移植性問題と機能性問題を解決できる

POSIX で規定された API やコマンドを直接使ってアプリケーションを開発するということは、自分で移植性問題を解決する面倒くさい作業です。実際の環境でテストすることを考えるとこれはとても大変だというのは言うまでもないでしょう。

C 言語で開発されたソフトウェアの場合 OS のシステムコールを直接呼び出すことはあまりなく 標準 C ライブラリまたはサードパーティのライブラリ経由で呼び出すのが一般的ですが、シェルスクリプトの場合 OS に標準でインストールされているコマンドを使うことが多いです。POSIX が OS の互換性を完全に解決するものではない以上 **OS のコマンドを直接使うシェルスクリプトが OS 依存が激しいのは当然の結果**であると言えます。

そこで一般に用いられている手段が、移植性問題に対応した「他の言語を使う」「ライブラリを使う」「コマンドを使う」と言った手段です。Java の考え方もこれと同じです。

![image9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/4d6c87a1-8f2c-d50f-85bd-93efe1b7c1a5.png)

これらの手段は POSIX が OS のインターフェースとしての必要最小限しか定義しないのとは異なり、OS 固有の拡張機能も含めて POSIX の範囲よりも広い範囲を対象としています。対応範囲が大きく異るという点で POSIX では解決不可能な問題を扱っており POSIX の目的とは全く違うものです。POSIX で規定されたものだけを使うという考えは「他の言語を使う」「ライブラリを使う」「コマンドを使う」の代替にはなりません。一言でいうならば **POSIX だけで頑張るのは大変すぎる**ということです。

もちろん、他人が作ったものを使う代わりに自分で言語を作ったりライブラリを作ったりコマンドを作ったりしても構いませんが、すでに存在しているソフトウェアと同じことしかしないソフトウェアを作っても車輪の再発明でしかなく、他人が作ろうが自分が作ろうが本質的には何も変わりません。独自技術症候群にならないように気をつけてください。使う側の立場になれば同じことをするソフトウェアが複数あればより実績が多い方を選ぶのは当たり前です。そのようなものを自作した所で自分以外誰も使いません。

### POSIXコマンドはどの環境でもインストールされているコマンドではない

おそらく多くの人が本当に欲しいものは「POSIX 準拠」ではなく「OS の基本構成（最小構成または標準構成）で動くこと」ではないでしょうか？ユーザーに OS のセットアップ作業させる必要もなく、ソフトウェアを動かすことが出来るのであればそれは便利でしょう。

しかしそれはソフトウェアを使う上での利便性の話であって POSIX 準拠の話とは全く関係ありません。また OS の最小構成で使えるコマンドは POSIX で規定されたコマンドのよりも遥かに少ないです。**POSIX準拠の OS であっても最小構成のインストールで POSIX で規定されているコマンドがすべて使えるわけでは有りません**。POSIX には「POSIX コマンドは必ずインストールされていなければならない」という規定はありません。

![image10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/a912d7c1-25ad-3da5-4696-e96077f79a46.png)

以下のコマンドは POSIX で規定されており比較的よく使われるコマンドですが、**OS の最小構成では使えない場合があるコマンド**です。

```text
at bc c99 cal compress crontab csplit file getconf iconv join
make man more patch pax ps strings tput uncompress vi
```

POSIX で規定されているコマンドであっても最小構成に含まれるとは限らないので、**POSIX コマンドだけを使ったシェルスクリプトであってもインストール直後の環境から動くとは限りません**。C 言語で開発されたソフトウェアであればおそらく動くとは思いますが、例外がないとは言い切れないと思います。

また OS の基本構成で動かなければいけないソフトウェアが必要になるのは、環境の初期設定スクリプトやパッケージを自由にインストールできないシステムで動かすスクリプトぐらいなものです。**コマンドがインストールされていないならインストールすればよいだけ**です。そのためにパッケージ管理システムがあるわけでインストール作業の手間など無いに等しいものです。そしてどちらにしろコマンドをインストールするのであれば POSIX コマンドだけに限定する必要はありません。多くの環境に移植済みの「POSIX 準拠」アプリケーションはたくさんあります。そういった POSIX 準拠アプリケーション（POSIX 準拠コマンド）を使えば、わざわざ自分で作る必要がなくなります。現代のシステム開発はそういったさまざまなアプリケーションを使うことが重要な鍵です。オープンソースの普及により昔のように高額なソフトウェアを購入する必要もなくなっており、今まで使っていたソフトウェアが急に使えなくなることもないので、他の人が開発したアプリケーションを利用する際の懸念点はかなり小さくなっています。

特にウェブサーバーや `curl` や `wget` コマンドをインストールしなければ使えないシェルスクリプトの場合、どちらにしろ「OS の基本構成だけで動く」を満たすことは出来ません。何かしらのパッケージをインストールしなければ動かないシェルスクリプトであれば OS の最小構成で動くようにすることに意味はありません。OS の基本構成で動くことを気にするのは、限られた特定のソフトウェアには意味があると思いますが、POSIX コマンドであっても OS の最小構成で動くとは限らない以上、POSIX とはまったく関係ない話なのです。

## POSIX の定義を自分の目で確かめてみよう！

さて、この記事で解説したことが POSIX にどこに書いてあるのかを見ていくとしましょう。これらを読むことでこの記事の内容が私の独自解釈ではないことがわかるはずです。この記事の内容に疑問を持った場合はこれらを参照してください。

この記事の内容は主に以下の 2 つのページ及び、それらの Rationale（理論的根拠）で定義されています。

- [Introduction](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html) ([Rationale](https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap01.html))
- [Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html) ([Rationale](https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap02.html))

### 基本

#### POSIX 準拠と XSI 準拠の違い

POSIX 準拠と UNIX 認定は厳密には異なっており XSI とは UNIX 認証のためのオプションの追加仕様です。

UNIX 認定の要件として POSIX 準拠である必要があるため、UNIX 認定を受けている場合は POSIX 準拠と言えますが、POSIX 準拠だからといって UNIX としての要件を満たしているわけでは有りません。POSIX + XSI（+ α）を満たして初めて UNIX の認定を得られる要件を満たします。

- [POSIX™ Certification Register](http://get.posixcertified.ieee.org/register.html)（POSIX 認定）
  - 要件は POSIX 準拠のみ
- [UNIX® Certified Products](https://www.opengroup.org/openbrand/register/)（UNIX 認定）
  - 要件は POSIX + XSI + α

POSIX と XSI の違いの一つに `echo` コマンドがあります。Linux などの `echo` は `-n` オプションは、一般的に「改行をしない」という意味のオプションですが POSIX では `-n` の動作は「未規定 (unspecified)」であるため改行しても改行しなくてもそれ以外の動作でも POSIX 準拠です。一方 XSI の仕様では `-n` という文字列として扱うと規定されているため UNIX の認証を取得している macOS の `/bin/sh` では XSI の要求通り `echo -n` は `-n` という文字列を出力します。

```sh
# Linux 等
#   多くのシェルでは改行しないという意味だが
#   正確な定義は未規定なのでどのような動作でも POSIX 準拠
$ echo -n "12" && echo -n "34"
1234

# macOS の /bin/sh
#   UNIX 認証のために XSI に準拠しており、そのまま文字列として出力
$ echo -n "12" && echo -n "34"
-n 12
-n 34
```

### 用語の定義

用語は [1.5 Terminology](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05) で定義されています。

- 実装定義 [implementatdion-defined](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_02)
- 未定義 [undefined](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_07)
- 未規定 [unspecified](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_08)
- レガシー [legacy](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html#tag_01_05_03)

can, may, shall, should と言った仕様でよく見かける用語の定義もここで行われています。

### OS ベンダー向けの POSIX 準拠の要件

[2.1 Implementation Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01)

これは OS を実装する側にとっての要件です。

[Rationale](https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap02.html#tag_21_02_01) には「厳密に 準拠した OSの実装（strictly conforming implementation）」という定義はないと書かれています。これは POSIX に規定されたものだけを実装した OS にはシステム管理機能がないため OS として使い物にならないからです。**POSIX に準拠した全ての OS は「拡張機能」を実装しています**。

#### 要件

[2.1.1 Requirements](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_01)

OS の実装者が満たさなければいけない要件が書かれています。

> Non-standard extensions, when used, may change the behavior of utilities, functions, or facilities defined by POSIX.1-2017. The conformance document shall define an environment in which an application can be run with the behavior specified by POSIX.1-2017. In no case shall such an environment require modification of a Strictly Conforming POSIX Application.

少し解釈が難しいですが、私の理解では OS を実装する際に**POSIX に準拠していない互換環境を実装してもよい**が POSIX に準拠していると主張するのであれば、**POSIX に完全に準拠した環境も用意し**「厳密に準拠した POSIX アプリケーション」がそのまま動くようにしろということを言っているのだと思います。これは特に商用 UNIX で重要な話だと思います。例えば歴史的な Unix（System V 系）の `tr` コマンドは文字の範囲を指定する場合 `[0-9]` のように括弧が必要なのですが POSIX に準拠では `0-9` が正しい指定方法です。商用 UNIX では互換性維持のために System V 系の動作をデフォルトとしていることが多いようですが、これだと POSIX に準拠していないことになってしまいます。しかし設定を行うなどの方法で **POSIX 準拠の環境が利用可能であれば POSIX 準拠の OS と認める**という話をしているのだと私は解釈しています。実際 Solaris ではデフォルトでは POSIX に準拠していない互換環境ですが、環境変数 `PATH` を適切に設定することで POSIX 準拠の環境に変更することができます。

#### ドキュメント

[2.1.2 Documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_02)

> The conformance document may specify the behavior of the implementation for those features where POSIX.1-2017 states that implementations may vary or where features are identified as undefined or unspecified.

POSIX には仕様が未定義または未規定となっている項目がありますが、その項目に関しては OS の実装者がその動作を指定しても良いということです。つまり POSIX では動作が決まっていなくても、実際の実装では決まっていることがあるということです。

#### POSIX 準拠の OS

[2.1.3 POSIX Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_03)

POSIX 準拠の OS のための細かい要件が書かれています。

#### XSI 準拠の OS

[2.1.4 XSI Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_04)

準拠の基準が POSIX 準拠から XSI 準拠に変わっただけです。

### アプリケーション開発者向けの POSIX 準拠の要件

[2.2 Application Conformance](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02)

アプリケーション開発者向けの POSIX 準拠の要件です。

#### 厳密な POSIX 準拠のアプリケーション

[2.2.1 Strictly Conforming POSIX Application](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_01)

この記事で解説した「厳密な POSIX 準拠のアプリケーション」の要件です。

#### POSIX 準拠のアプリケーション

[2.2.2 Conforming POSIX Application](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_02)

さらに以下の二つのカテゴリがありますが、実を言うとこの定義の意味はよくわかっていません。重要なことなのかもしれませんが、本記事で解説したいこととは直接関係ないと思われるので深追いはしていません。

- ISO/IEC Conforming POSIX Application
- \<National Body\> Conforming POSIX Application

#### 拡張機能を利用する POSIX 準拠のアプリケーション

[2.2.3 Conforming POSIX Application Using Extensions](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_03)

この記事で解説した「拡張機能を利用する POSIX 準拠のアプリケーション」の要件です。

> Such an application shall fully document its requirements for these extended facilities, in addition to the documentation required of a Conforming POSIX Application. 

拡張機能を利用するアプリケーションは、拡張機能に対する要件を文書化しなければいけないと書かれています。

#### 厳密な XSI 準拠のアプリケーション

[2.2.4 Strictly Conforming XSI Application](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_04)

要件の基準が POSIX 準拠から XSI 準拠に変わっただけです。

#### XSI 準拠のアプリケーション

[2.2.5 Conforming XSI Application Using Extensions](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_05)

要件の基準が POSIX 準拠から XSI 準拠に変わっただけです。

## まとめ

この記事では以下のことを明らかにしました。

- 「厳密な POSIX 準拠アプリケーション」は OS の拡張機能は使えないがアプリケーションに分類されるものは自由に使える
- 「拡張機能を利用する POSIX 準拠アプリケーション」は上記に加えて OS の拡張機能を使っても POSIX 準拠である
- POSIX で規定されていない OS のインターフェースが「拡張機能」である
- C 言語とシェルスクリプト以外の言語を使っても、内部で POSIX API しか呼び出していないのであれば POSIX 準拠である
- OS の最小構成や基本構成で動かすことと POSIX は関係ない

POSIX で規定されているものは OS のインターフェースだけであり、ソフトウェア開発においてごく僅かの範囲しか対象となっていません。もし POSIX で規定されているものしか使ってはいけないのであれば、多くのソフトウェアは POSIX に準拠できないことになってしまいます。それは移植性が高いアプリケーションを作れるようにしたはずの POSIX の方針と矛盾しています。

多くの言語、多くのライブラリ、多くのコマンドが多くの POSIX 準拠 OS で動いています。実際にどこでも動いているソフトウェアであれば、それは POSIX に準拠していると言って間違いないでしょう。POSIX 準拠とは「POSIX で規定されているものだけを使う」ことではありません。