Unix哲学「一つのことをうまくやる」は単機能のコマンドを作ることではない

## はじめに

Unix 哲学には [DOTADIW: Do One Thing and Do It Well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well) という言葉があります。日本語に訳すと「一つのことをうまくやる」となりますが、しばしば**単機能のコマンドを作ることだと勘違い**されています。もし勘違いしている人がいるのであれば、ぜひその人に聞いてみてください。なぜ `grep` コマンドはマッチした行数をカウントする機能を昔から持っているのですかと。昔からある `wc` コマンドがあれば `grep` コマンドに行数をカウントする機能をもたせる必要はないのではないかと。

https://man.cat-v.org/unix_7th/1/grep

> -c   Only a count of matching lines is printed.

https://man.cat-v.org/unix-1st/1/wc

> 	wc provides a count of the words, text lines, and roffcontrol lines for each argument file.

複数の機能を持っているのは `grep` コマンドだけではありません。多くのコマンドが複数の機能を持っています。そしてコマンドがバージョンアップすると大々的に「新しい機能 (new features) が追加されました！」と宣伝されます。ほぼすべてのコマンドが最初のバージョンから「機能」が追加されています。それが真実です。現実をよく見据えれば、**「一つのことをうまくやる」が「単機能のコマンドを作ること」だと矛盾してしまう**ことに気づくはずなのです。

この記事ではなぜ「一つのことをうまくやる」が「単機能のコマンドを作ることではない」かを解説します。ところで DOTADIW という単語はぜんぜん覚えられないのですがドタディウと発音すればよいのでしょうか？

## パイプの誕生とUnix哲学の4つの考え方

Unix 哲学には「これが Unix 哲学である」という定義があるわけではありませんが、1973 年のパイプの誕生を契機として「ソフトウェアツール」という考え方が生まれ、ここから Unix 哲学と呼ばれる考え方が広まったことはよく知られています。パイプの発案者は Unix が開発された AT&Tベル研究所の Doug McIlroy であり、彼が 1978 年の Bell System Technical Journal の「[UNIX Time-Sharing System: Forward](https://archive.org/details/bstj57-6-1899/mode/2up)」で文書化した次の 4 つが Unix 哲学の考え方として有名です。McIlroy の言葉を引用せずに Unix 哲学を語ることはできません。

> Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".

**訳** それぞれのプログラムは一つのことをうまくやれ。新しい仕事をするには古いプログラムに新しい「機能」を追加して複雑にするのではなく新しく構築せよ。

> Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.

**訳** すべてのプログラムの出力はまだ知らないその他のプログラムの入力になることを予測せよ。余計な情報で出力を乱雑にしてはいけない。厳密な固定長やバイナリの入力形式を避けよ。対話的な入力にこだわるな。

> Design and build software, even operating systems, to be tried early, ideally within weeks. Don't hesitate to throw away the clumsy parts and rebuild them.

**訳** ソフトウェアの設計と構築を、例えオペレーティングシステムであっても、早くに理想的には数週間以内に試せるように行え。使い勝手の悪い部品を捨てることをためらわず、それらを再構築せよ。

> Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them.

**訳** プログラミング作業を軽くするために未熟な人の助けよりも道具を優先して使用せよ。たとえ道具を作るために回り道をしなければならず、使い終わった後にそのうちのいくつかを捨てることになると予想していたとしても。


## 「単機能のコマンドを作る」ではない理由

「DOTADIW: 一つのことをうまくやる」が「単機能のコマンドを作ること」でない理由は、McIlroy による定義から明らかです。再掲します。

> Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".

それぞれのプログラムは **一つのこと (one thing)** をうまくやれ。**新しい仕事 (new job)** をするには古いプログラムに**新しい「機能」 (new "features")** を追加して複雑にするのではなく新しく構築せよ。

このように「一つのこと」と「新しい機能」は異なる単語です。そしてもう一つ重要なのは、一つのことをうまくやるコマンドに機能を追加してはいけないと言っていないということです。追加していけないのは「新しい仕事」をするときです。本来そのコマンドが行うべき仕事**ではない**新しい仕事をする時に機能を追加して複雑にしてはいけないということです。

新しい機能を追加して複雑にしてしまった例として有名なのが `cat` コマンドの `-v` オプションです。この話は 1983 年の「[UNIX Style, or cat -v Considered Harmful](https://harmful.cat-v.org/cat-v/)」と論文「[Program Design in the UNIX Environment](https://harmful.cat-v.org/cat-v/unix_prog_design.pdf)」で詳しく語られています。著者は Rob Pike と Kernighan
です。`-v` オプションは（おそらく） 1982 年の [2.9BSD Unix](https://www.tuhs.org/cgi-bin/utree.pl?file=2.9BSD/usr/src/cmd/cat.c) か [4BSD Unix](https://www.tuhs.org/cgi-bin/utree.pl?file=4BSD/usr/src/cmd/cat.c) あたりで追加されたオプションです。System III 版にはありませんし、System V 版にはありますが 1983 年リリースです。GNU プロジェクトの開始も 1983 年です。`-v` オプションは印刷不可能な文字を人が読める文字（`^A`など）に置き換えて出力するオプションですが、**`cat` コマンドは本来ファイルを結合して出力するコマンド**であるため、データを加工する機能は新しい仕事となり `cat` コマンドに追加するべきではないとなります。
 
## 「単機能のコマンドを作る」は誤訳だった

いくつかの本の日本語訳版で「一つのこと」を「単機能」と誤訳している例を見つけることができます。

### 誤訳本1: UNIXの¼世紀

Wikipedia（英語版）の [Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy#Origin) のページには、「A Quarter-Century of Unix (1994)」の著者である Peter H. Salus が、McIlroy の言ったことを Unix 哲学として次のようにまとめていると記されています。

> It was later summarized by Peter H. Salus in A Quarter-Century of Unix (1994):[1]
> 
> - Write programs that do one thing and do it well.
> - Write programs to work together.
> - Write programs to handle text streams, because that is a universal interface.

**訳** （私による訳）

- 一つのことをうまくやるプログラムを書く
- 一緒に動作するプログラムを書く
- テキストストリームを扱うプログラムを書く、なぜならそれはユニバーサルインターフェースだから

「A Quarter-Century of Unix」は https://wiki.tuhs.org/doku.php?id=publications:books で [PDF](https://wiki.tuhs.org/lib/exe/fetch.php?media=publications:qcu.pdf) が公開されているので誰でも読むことができます。同書は日本語にも翻訳されており「UNIXの¼世紀」として 2000 年に出版されています。ではどのように翻訳されているかを見てみましょう。P64 からの引用です。

> Unix 哲学
>
> - 1 つの機能を確実に実行するプログラムを書く。
> - ほかのプログラムと一緒にどうさするプログラムを書く。
> - テキストストリームを処理するプログラムを書く。それが、汎用的なインターフェイスだから。

同書は他にも「一つのこと」と訳すべきところを「1つの機能」と訳しています。同書が one thing を一つの機能と訳してしまった最初の例ではないかもしれませんが、wikipedia に書かれているぐらいですから、よく参照されている（されていた）本の一つであることに間違いはないでしょう。Amazon にはこのようなレビューもあります。さんざんな言われようですねｗ

> <img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54918/c51360e4-bfaa-2cef-572c-828569cf0ed7.png">

### 誤訳本2: UNIXという考え方

もう一つの有名な本での誤訳の例は 2001 年に日本で出版された「UNIXという考え方」です。原著のタイトルは「The UNIX Philosophy」で 1994 年に出版された本です。著者の Mike Gancarz は今はなき DEC 社のプログラマだった人で、当時は自社のコンピュータ用に Unix を移植していたようです。同書は当時の Unix に関係するプログラマの考えや自身の信念を Unix 哲学としてまとめたものです。P23 にはこうあります。太字は私によるものです。

> 　最良のプログラムは、クストーのレイク・フライのように、生涯において一つのことをうまくやるプログラムだ。プログラムはメモリにロードされて、所定の働きをし、次の**単一機能**のプログラムの実行のために道を譲る。簡単に聞こえるが、ソフトウェア開発者が**単一機能**プログラムを作り上げることだけを追求し続けること、これがいかに難しいことかを知ったら驚くかもしれない。

単一機能という言葉が使われていますが、原著のP23（おぉ、日本語版と同じページだ）では次のようになっています。ただし私が持っているのは 2003 年に出版された第2版の「Linux and the Unix Philosophy」なので微妙に文章が異なる可能性があります。

> The best program, like Cousteau's lake fly, performs but one task in its life and does it well. The program is loaded into memory, accomplishes its function and then gets out of the way to allow next **single-minded** program to begin. This sounds simple, yet it may surprise you how many software developers have difficulty sticking to this **singular** goal.

single-minded は「ひたむきな」などという意味があるようですが、ここでは直訳で「一つの精神の」とか「一つの考えの」とか「一つの目標の」として方が良いかもしれません。いずれにしろ「単一機能のプログラム」ではありません。二番目の「単一機能のプログラム」は原著では sigular goal（唯一のゴール）なので文章自体が違っています。同書は正しく「一つのこと」と訳している部分もあるのですが、ところどころ単一機能という言葉が出てきます。

## 一つのことをうまくやっているコマンドの例

一つのことをうまくやっているコマンドの例を紹介します。

### grep コマンド・sed コマンド

Unix 哲学およびソフトウェアツールの考え方はパイプの発明とともに誕生しました。その初期の例が `grep` コマンドです。`grep` コマンドは `ed` コマンドから検索機能だけを取り出して作られた一つのことをうまくやるコマンドです。しかし同時期に作られた `sed` コマンドは `ed` コマンドが持っている、おそらくほとんどの機能を持っている多機能なコマンドです。`grep` と同じこともできますし、パターンスペースやホールドスペースの 2 つしかないとはいえ変数を持っていますし、ラベルと goto に相当する機能を持っています。

このように `grep` コマンドと `sed` コマンドには設計方針に違いがあるように見えます。しかし **`sed` コマンドは McIlroy が認めた一つのことをうまくやるコマンド**です。これはコマンドが持っている機能の数と Unix 哲学は直接の関係はないことを意味しています。`sed` コマンドに関しての話は別の記事を書きたいと思っているので詳細は割愛しますが興味がある人は検索してみてください。

### awkはUnix哲学に従ったスクリプト言語

Unix 哲学に従ったコマンドのもう一つの例は `awk` コマンドです。`awk` コマンドはプログラミング言語なので多くの機能を持っていますが、これも一つのことをやっているコマンドです。2024年5月16日に発売された「プログラミング言語 AWK 第2版」にまえがきにはこのように書かれています（太字は私によるもの）。

> Awk は 1977年（昭和52年）、小規模なプログラムを対象に、テキストも数値も容易に操作できる簡易なプログラミング言語として開発された。**1 プログラムは 1 つの仕事しかこなさず、他のプログラムと連携、組み合わせるという Unix の哲学に沿い、他の Unix ツールと調和しお互いに補完し合うスクリプト言語 (scripting language)** を意図していた。

「昭和52年」という単語から訳者による追加の文章ではないかと考えるかもしれませんが、 原著の Preface（https://www.amazon.co.jp/dp/0138269726 から見られます）にも同様の文章があります。

「Awk の開発者は Unix 哲学の道を踏み外したんだ！」という主張をするのはかなり難しいことです。なぜなら同書の著者であり awk の開発者である Alfred Aho、Brian Kernighan、Peter Weinberger の 3 人の中の  **Kernighan は「Software Tools」（日本語訳は「ソフトウェア作法（さくほう）」）の著者**でもあるからです。先程の `cat -v` が Unix の考え方を踏み外しているという論文を書いた人の一人でもあります。補足ですが一般的には「プログラミング言語 C」や「プログラミング言語 Go」の著者として有名です。

Unix 哲学に近い人物が `awk` を Unix 哲学に沿って作ったと言っているのですから、その人に対して Unix 哲学を理解していないなんてとても言えたものではありません。ちなみに「プログラミング言語 AWK 第2版」では awk の**新機能**として Unicode 対応と CSV 対応の話が書かれています。この 2 つの機能の追加に関しては Kernighan も関わっています。

## さいごに

一つの機能しか持たないコマンドは一つのことしかできないため Unix 哲学として理想的ではあります。しかし、なるべく少ない機能をもたせようと考えていたとしても、コマンドには機能が追加され複雑になる運命にあります。だからこそ新しい仕事である無関係な機能を追加したりして、複雑にしてしまわないようにしろと言っているわけです。重要なのは追加する機能がそのコマンドの仕事として適切であるかです。単機能のコマンドは理想的ではあっても、大抵の場合は現実的ではありません。Unix 哲学を正しく理解すれば、多数の機能を持っている `sh`（シェル）、`perl` なども `sed`、`awk` と同じように「一つのことをうまくやる」コマンドだと理解できるはずです。比較的最近（？）の例では `jq` コマンドも一つのことをうまくやっている Unix 哲学をよく理解して作られているコマンドです。

Unix 哲学を理解するというのは案外難しいことです。Unix 哲学は設計方針ではなく定義もないため、唯一と正しいと言える原則や定理などというものはありません。ただでさえ理解するのが難しいというのに、日本では誤訳が広まっているため間違った理解をしている人は少なくありません。日本で出版されている本、大学やセミナーなどで教えている内容にも間違いや古い情報が含まれていることが多々あります。可能な限り原著を、できれば最新の本を参照することをおすすめします。とはいうももの Unix 哲学が盛んに言われていた時代はずいぶんと前の話であり、今は Unix 哲学が通用しない分野も多く、「いまさら Unix 哲学？」な状態なので、なかなか難しい話ではありますが。