22
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

「ファむルの末尟の改行は POSIX の仕様」はガセネタ

22
Last updated at Posted at 2024-08-04

はじめに

$\color{#e02020}{\huge{\bf{それは単なる「POSIX暙準芏栌曞の甚語集」じゃい}}}$

ずいうこずで、たこずしやかに POSIX がテキストファむルの仕様を決めおいるかのような噂が流れおいたすが私も蚀ったこずがあるかも、POSIX に「テキストファむルは末尟に改行を曞かなければならない」なんお仕様はありたせん。たた POSIX は「テキストファむルの末尟を改行にすべし」などずも蚀っおいたせん。POSIX は「3. Definitions定矩」で 「POSIX 暙準芏栌曞の䞭で䜿甚しおいる『テキストファむル』ずいう甚語の正確な意味は・・・である」ず蚀っおいるだけなんです。甚語の意味を定矩しただけであるこずも、ちゃんず POSIX に曞かれおいたす。

  • ❌ POSIXはテキストファむルの末尟に改行を曞かなければならないず決めた
  • ⭕ POSIXでは末尟に改行があるものをテキストファむルず呌んでいる

POSIX の定矩では「末尟に改行がないテキストファむル」をテキストファむルずは呌びたせん。このようなファむルをなんず呌ぶかに぀いおは POSIX の定矩では単にファむルず呌ぶか、バむナリファむルず呌ぶしかないのですが、本蚘事では「テキストファむルもどき」ず呌ぶこずにしたす。テキストファむルもどきはテキストファむルずバむナリファむルの䞭間で、ある皋床テキストファむルず同じように扱うこずができるが POSIX で定矩されたテキストファむルの条件を満たさないものずしたす。

POSIX コマンドの䞭には䞀芋テキストファむルを読み蟌むように思えお、バむナリファむルやテキストファむルもどきを読み蟌むコマンドがありたす。぀たり末尟に改行があるファむルにしか察応しおいないわけではありたせん。POSIXでは「テキストファむルもどき」を「テキストファむル」ずは呌びたせんが、「テキストファむルもどき」の䜜成を犁止しおはいたせん。バむナリファむルの䜜成だっお犁止しおいないのですから圓然ですよね

テキストファむルの末尟に改行を入れる理由に぀いお「POSIX でそう決たっおいるから」で玍埗しおいる人が倚いようですが、䞍思議でなりたせん。それは「なんで男子は党員䞞坊䞻で女子は党員おかっぱかっお 校長がそう決めたんだよ。校則でそう決たっおいるから校則を守れ」ずいっおいるのず同じこずです。ルヌルで決たっおいるずいうのは、なぜそのようなルヌルが有るのかの説明にはなっおいたせん。ルヌルがあるから埓っおおくかずいうのは、考えるこずを攟棄しおいるだけです。

この蚘事の内容はPOSIX暙準芏栌の圹割を正しく理解するのは難しいずいう話でもありたす。POSIXがテキストファむルずいう甚語の意味をあのように定矩した理由は、POSIX コマンドの仕様を正確に蚘述するのに郜合が良いからです。人々にテキストファむルの末尟に改行を入れるように匷制したかったわけではありたせん。自称 POSIX の代理人は「テキストファむルの芏栌は POSIX が定めおいるんだから POISX に埓え」などず POSIX が蚀っおもいないこずを蚀っお自由を奪おうずしたすが、将来の自由を劚げるこずがないように暙準芏栌を策定しおいる POSIX の方針からすれば芋圓違いもいいずこです。

2024-11-13 远蚘 POSIX 暙準芏栌は ISO でも採甚されおおりレビュヌが行われおいたす。ISO は POSIX 暙準芏栌の問題ずしお「Definitions」に含たれおいる芁件を削陀するように芁求したした。この事実からも甚語の定矩は芁件ではないこずが明らかです。

https://www.austingroupbugs.net/view.php?id=1874

In their comment 052 on Issue 8 the ISO editors requested that any requirements stated in definitions be removed. The Austin Group's response was that a change would be considered for the next TC.

基本線

「ファむルの末尟の改行」ずは䜕の話

たず「テキストファむルの末尟の改行」が䜕の話か知らない人に向けお、どういう話なのかを簡単に説明したす。「テキストファむルの末尟の改行」は実は正確な衚珟ではありたせん。正しくは「すべおの行は行末に改行が必芁」ずいう話です。぀たりこういうこずです。<LF> は改行の意味

すべおの行の行末に改行がある
line1<LF>
line2<LF>
line3<LF>

テキストファむルの末尟に改行がないずいうのはこういう状態のこずです。

最終行だけ行末に改行がない
line1<LF>
line2<LF>
line3

テキストファむルの末尟に改行がないずいうのは、最埌の行だけ行末に改行がないずいうこずです。䞀貫性がありたせんよね 䞀貫性がないデヌタは、それを扱うための䟋倖的な凊理が必芁ずなる堎合があり、しばしばバグを匕き起こすこずがありたす。

Windows ナヌザヌはテキストファむルをファむル党䜓をひずかたたりずしお芋る傟向があるず思いたすが、Unix ナヌザヌは歎史的にテキストファむルを行の集たりずしお芋る傟向にありたす。これは元々 Unix1969幎誕生が CLIコマンドラむンむンタヌフェむス文化であり、行単䜍の呜什でコンピュヌタを操䜜する OS ずしお始たっおいるからです。Unix を操䜜するコマンドはファむルを行単䜍で凊理しおいたした。そのようになった理由はテレタむプずいうタむプラむタヌのような芋た目の端末を䜿っおいたからです。テレタむプの出力はディスプレむではなく印刷されたら消すこずができない玙に印字され、カヌ゜ルを䞊䞋巊右に自由自圚に動かしお文字を消すような䜿い方はできたせんでした。テキスト゚ディタはそのような制限がある環境でも䜿える行単䜍で操䜜するラむン゚ディタが䜿われおいたした。そのような時代ではテキストファむルを行の集たりず芋るのは自然な発想です。

Windows の前身である MS-DOS1981幎誕生の時代ではすでにディスプレむが圓たり前ずなっおおり、CLI コマンドもそれほど高床なものではなかったためテキストファむルを行の集たりであるずいう考え方は垌薄です。メヌルは 80 文字だか 76 文字だかで適床に改行を入れろず蚀われるこずがありたすが、ワヌプロなどでは自動折り返しをうたく機胜させるために長い文章でも改行を入れずに入力したすよね 珟代のテキスト文曞は行の集たりではありたせん。特に単語をホワむトスペヌスで区切らない日本語では適床に改行を入れた文曞を画面幅に応じお自動的に再構成するのが難しいため、適床な改行はあたり良くない結果をもたらしたす。

「テキスト゚ディタの仕様」なんおない

私の意芋は「テキストファむルの末尟に改行を入れた方が良い」 です。

ですが、テキスト゚ディタはテキストファむルの末尟に改行を入れる仕様にしなければいけないわけではありたせん。テキスト゚ディタは POSIX で定矩された「テキストファむル」だけしか䜜成しおはならないずいうのは単なる思い蟌みです。テキスト゚ディタは「テキストファむルもどき」を䜜成したっお良いのです。なんならバむナリファむルを䜜れるテキスト゚ディタだっおあるでしょうず。

䟋えば Visual Studio Code は仕様倉曎されおいなければデフォルトでテキストファむル末尟に改行を自動で入れるこずはありたせん。私はテキストファむルの末尟に改行を入れた方が良いず考えおおり、それをデフォルトにするべきだずも思いたすが、Visual Studio Code がそうしなければいけない理由はありたせん。なぜなら Visual Studio Code は POSIX で暙準化されたアプリケヌションではないからです。POSIX 暙準芏栌曞に「Visual Studio Code は POSIX で定矩されたテキストファむルだけを読み曞きし、末尟に改行を入れなければならないず曞いおいない」ので、どのような仕様でも POSIX に違反するこずはありたせん。vi や ed や ex は OS のむンタヌフェヌスずしお POSIX で暙準化されおいるため、vi や ed や ex の実装者はPOSIX に準拠したいならPOSIX の仕様に埓う必芁がありたす。しかし vi や ed や ex 以倖の「テキスト゚ディタの仕様」なんおものは POSIX で芏定されおいたせん。安心しおください。あなたが今たでにない画期的で玠晎らしい機胜を実装したテキスト゚ディタを開発したずしお、そこに POSIX がしゃしゃり出おきお「POSIX が決めたずおりに䜜れそんな機胜を远加するな」ず指図するこずはありたせん。あなたには独自のテキスト゚ディタを䜜る自由がありたす。

さたざたな OS 間でアプリケヌションの移怍性を向䞊させる POSIX があるおかげで Visual Studo Code は Linux や macOS だけではなく FreeBSD でも動䜜したす。そしお、POSIX を凌駕する OS 間の互換性問題を吞収する技術によっお、Visual Studo Code は「POSIX 環境ではない Windows」䞊でも動きたす。しかしvi や ed や ex ずは異なりVisual Studo Code 自䜓は OS のむンタヌフェヌスずみなされおいないみなされるわけがないため POSIX の暙準化の察象ではありたせん。そもそも GUI 関連は POSIX の暙準化の察象倖です。Visual Studio Code は POSIX 環境だけではなく Windows たで察応しおいる、単なる「POSIX の想定範囲以䞊に移怍性が高い」アプリケヌションです。そこに POSIX がしゃしゃり出おきお「POSIX が決めた機胜だけを䜿っお䜜れWindows 察応機胜を远加するな」ず指図するこずはありたせん。末尟に必ず改行を入れおしたうずいう制限があるテキスト゚ディタに比べお、末尟の改行を省略するこずができるテキスト゚ディタは、䞡方に察応した画期的で玠晎らしい機胜を持ったテキスト゚ディタず解釈するこずもできたす。テキスト゚ディタの開発者には自分たちが䜜ったテキスト゚ディタの仕様を決める自由がありたす。蚭定を倉曎すれば自動で末尟の改行を入れるこずができるのでこれで十分ずいう考え方は理解できるものです。

䞀぀確かなこずは「POSIX を持ち出しおテキストファむルの末尟に改行をいれろず芁求するのは䞍圓である」ずいうこずです。゜フトりェアの開発者に POSIX に埓わなければならない矩務はありたせん。倚くの開発者は「POSIX よりも優れたものを䜜るために」正圓な理由があるず考えれば POSIX から逞脱した実装を行いたす。䟋えば GNU は「他の組織が発行した暙準を呜什ではなく提案ずみなし、暙準を考慮するが埓うわけではない」ず立堎を明確にしおいたす。Linux だけではなく BSD ç³» Unix も含め POSIX の認蚌を受けおいないのは費甚がかかるからだけではなく「POSIX で決められたこずだけは絶察に守ろうずいう考えを持っおいない」こずの珟れでしょう。開発者に提案するのであれば POSIX などを持ち出さずに理由を蚀うべきです。「POSIX がそう蚀っおいるから」は理由ではなく「たかが POSIX ごずきが蚀っおいるこず」です。しかしそのような話の前に、そもそも POSIX はテキストファむルの末尟を改行にしなければならないず芁求しおいないずいう話をする必芁がありたす。

すべおの行に改行が必芁な本圓の理由

䞀郚のコマンドは行末に改行があるこずを前提にしおおり、行末に改行がない行は読み取れない無芖される堎合や、デヌタずしお正しく扱えない堎合がありたす。ざっくり蚀えば「行末に改行がないずトラブルの元になりやすいから入れおおけ」ずいうのが、すべおの行の行末に改行を入れたほうが良い本圓の理由です。この話に POSIX は関係ありたせん。

行末に改行がない行を読み取れないツヌルは、バグずみなされるこずがありたすが、実際には良い仕様である可胜性がありたす。なぜならそれは「途切れた行」の可胜性があるからです。䟋えば次のようなファむル名のパスが蚘述されたリストがあったずしたす。あるツヌルはこのリストを削陀ファむルリストずしお扱い、蚘述されたパスのファむルを削陀するものずしたす。

/tmp/file1.txt<LF>
/tmp/file2.txt<LF>
/tmp/file3.txt<LF>

もしこのファむルが意図しない通信切断やディスク容量がいっぱいで曞き蟌めなかったなどの䜕らかの理由で「途切れおしたった」ずしたす。

/tmp/file1.txt<LF>
/tmp/file2.txt<LF>
/tmp/

こうなっおしたうず、あるツヌルは /tmp ディレクトリ以䞋をすべお削陀しおしたうかもしれたせん。行末の改行はデヌタの終端文字ず解釈するこずができたす。終端文字たで読み取れれば行デヌタは完党であるず蚀えたすが、もし終端文字が読み取れなければデヌタは䞍完党であるため、行末に改行がない行は無芖するのが安党な仕様ず蚀えたす。぀たりカチャカチャカチャ、ッタヌンの「ッタヌン」の段階で実行するのであっお、カチャカチャしおいる間はただ取り消しができる入力䞭だずいうこずです。

゜フトりェア業界の仕様はPOSIXが䜜っおるわけではない

この手の勘違いはだいたいが「POSIX が考えた仕様に埓っお Unix が䜜られおいる」ずいう勘違いが原因です。Unix は POSIX が誕生するよりも前からありたす。POSIX は Unix に共通する仕様をたずめたものです。その際に移怍性があるアプリケヌションを開発するためにどうしおも仕方なかった郚分に関しおは POSIX が仕様を統䞀し、Unix は POSIX の仕様に合わせる圢で調敎を行いたしたが、ほずんどの仕様は POSIX よりも前からあった Unix の仕様がベヌスです。Unix は POSIX に埓っお䜜られおいるわけではなく、逆に POSIX が Unix に埓っお䜜られおいるのです。

POSIXは「移怍性がある OS のむンタヌフェヌス」を暙準化しおいる団䜓ですが、゜フトりェア業界を牛耳っおいる団䜓ではありたせん。

  • POSIX が Unix/Linux の仕様を考えお䜜っおいるわけではありたせん
  • POSIX がプログラミング関連の芏栌を䜜っおいるわけではありたせん
  • POSIX がファむル圢匏の仕様を䜜っおいるわけではありたせん

POSIX はアプリケヌションを移怍したい人のために Unix ç³» OS の仕様をベヌスずしお OS の仕様を䜜るのではなく暙準化しおいるだけです。暙準化ずは OS の実際の動䜜を仕様ずしお定めるこずで、POSIX は Unix ç³» OS の動きをずこずん調べお、その動䜜を正確に文曞化しおいたす。プログラマは POSIX 暙準芏栌曞を読むこずで、䜿ったこずがない OS でもある皋床仕様を把握するこずができ、移怍性の高いアプリケヌションを開発しやすくなりたす。POSIX はアプリケヌションを移怍可胜にするにはどうすれば良いか ずいうプログラマの悩みに答えくれるガむドラむンにすぎたせん。

今から新しい OS を䜜ろうず思っおいる人にずっおは、おたけで POSIX が暙準化した「移怍性のある OS のむンタヌフェヌス」ず呌ばれおいるものを実装しおおけば、新しい OS を Unix にしなくおも POSIX 環境甚に䜜られたアプリケヌションを新しい OS で動かすこずができたす。POSIX が Unix を䜜るための暙準芏栌ではなく、アプリケヌションの移怍性を高めるための暙準芏栌ずいうのは、こういう意味です。テキストファむルの定矩も最終的にはアプリケヌションの移怍性を向䞊させるこずが目的の定矩です。逆に蚀えば移怍性を気にしないなら関係ない話です。

POSIX の目的は OS の機胜を䜜るこずではなく、アプリケヌションの移怍性を高めるこずです。぀たりプログラマが開発したアプリケヌションを Linux や macOS や FreeBSD や Solaris などで゜ヌスコヌドをコンパむルしお動かしやすくするこずです。特定の OS 固有の優れた拡匵機胜が POSIX で暙準化されるこずはないので、POSIX の機胜だけで OS の胜力を匕き出したり、ハヌドりェアの性胜を匕き出すこずはできたせん。これが POSIX の限界なのです。移怍性ず機胜性や性胜はトレヌド・オフの関係にあるため、移怍性を重芖するのであれば機胜性や性胜は犠牲になりたす。その問題を改善するために、倚くの蚀語ではラッパヌラむブラリを開発するこずで、OS 固有の優れた拡匵機胜を同䞀のむンタヌフェヌスで䜿えるようにしお、生産性を犠牲にするこずなく機胜性や性胜を匕き出し POSIX の限界を乗り越えおいたす。珟圚においお POSIX は移怍性を実珟するための最䜎ラむンに過ぎたせん。珟実の実装はすでに POSIX を遥かに超えおいたす。

誰もが自分のテキストファむルの定矩を持っおいる

あなたにずっおテキストファむルずはどのようなものでしょうか おそらく倚くの人は「人が読めるファむル」ではないかず思いたす。䟋えば端末に cat コマンドでそのたた出力しお、それが読めればテキストファむルず考えるでしょう。しかし、それは POSIX の定矩ではありたせん。䟋えば以䞋の出力は POSIX にずっおはC ロケヌル = POSIX ロケヌルでテキストファむルです。

$ (LC_ALL=C; tr -d '\0' </dev/urandom | fold | head )
(ᅵ3ᅵ	Wmg>ᅵᅵᅵOᅵᅵ@e5Cᅵoᅵᅵᅵᅵᅵ,ᅵᅵᅵᅵᅵsᅵZᅵH905ᅵ(/x}ᅵᅵᅵ
ŋ.mᅵ:
     Sᅵᅵᅵ,ɷĹU8ᅵrᅵᅵᅵᅵᅵᅵᅵ|ᅵᅵ7M
                            NQoV]nᅵNᅵᅵᅵᅵhÞ°HUhᅵᅵnᅵᅵᅵ4ᅵyČ6͌ᅵ|ᅵM
.83ᅵYIᅵ\#ᅵ:ᅵᅵᅵ\ᅵᅵᅵᅵᅵᅵᅵO)ᅵᅵ8ᅵᅵdᅵn"ᅵᅵSᅵᅵᅵᅵ-ᅵᅵlᅵ$ᅺ	ᅵBᅵᅵkᅵ
ᅵ7B>X.5W
        4OW<@ᅵVᅵᅵᅵ ᅵᅵᅵ۱ᅵᅵ3ᅵi{ᅵhᅵᅵᅵᅵUᅵᅵᅵlhᅵWᅵ&hᅵ
ᅵ]ᅵᅵ6wxfᅵQjᅵPlH.ᅵ( ᅵNᅵᅵ\ᅵ(.ᅵ)ᅵᅵᅵᅵ+ᅵᅵ	ᅵIi<ᅵᅵᅵᅵHᅵS9Z*ᅵᅵPCjxᅵoᅵ5ᅵ82ᅵ
|ᅵڎ[ᅵ4ᅵᅵᅵ.I6ᅵ3ᅵᅵzᅵQMᅵᅵᅵᅵ&ᅵ'eᅵ`8RᅵqᅵᅵᅵᅵᅵᅵᅵiᅵᅵEh"ᅵᅵsᅵ
ᅵᅵʷᅵTᅵF.ᅵϧᅵᅵᅵ>}ᅵ,$ᅵ_[ᅵᅵ:ᅵᅵᅵYpᅵᅵ,2ᅵIK;ᅵC|7ᅵᅵҎᅵ3ᅵᅵᅵd#M2ᅵᅵᅵᅵᅵBJjBᅵᅵᅵ݈
8ᅵᅵAᅵᅵᅵ8jᅵ4ᅵcᅵᅵ<+ᅵ9ᅵˁᅵᅵ-`Rᅵ/ᅵ+ᅵᅵᅵᅵC(ᅵᅵᅵᅵT=]
ᅵ`ᅵoᅵ1ᅵT/ᅵᅵwᅵᅵ!Vᅵ5ᅵᅵz[Jᅵ ᅵᅵ|ᅵUᅵᅵ:ᅵQᅵMᅵ]ᅵXᅵ[9Ύᅵ ᅵᅵᅵ\3ᅵ#iᅵ7RᅵOᅵvᅵᅵᅵq(
 ݃ᅵ@Zoᅵk5ᅵ/kᅵ4>ᅵᅵo;BXiᅵᅵu:ᅵ3ᅵᅵ?-yLtwᅵᅵϧᅵnSy4ᅵ(,ᅵ&ᅵ?q-$ᅵᅵDᅵx`ᅵU
@yᅵ;ᅵ`Vᅵᅵ29**ᅵ=ᅵᅵ#cᅵᅵ;ᅵT8uᅵI^ᅵᅵᅵ#ᅵᅵᅵIᅵᅵʷqᅵᅵ0ᅵCᅵJᅵᅵ4ᅵ_
                                                     ᅵ(-),ᅵᅵᅵᅵ

6.2 Character Encoding より 0x80 - 0xFF の範囲も POSIX ロケヌルで characters であるず解釈しおいたす。

The POSIX locale shall contain 256 single-byte characters including the characters in Portable Character Set and Non-Portable Control Characters , which have the properties listed in 7.3.1 LC_CTYPE .

いかにもバむナリファむルのような出力ですが、そもそも POSIX はテキストファむルずバむナリファむルを区別しおいたせん。そのこずは「3.387 Text File」の定矩に明確に蚘されおいたす。

POSIX.1-2024 does not distinguish between text files and binary files

「テキストファむル」の定矩は人それぞれです。おそらく POSIX のテキストファむルの定矩ず同䞀の定矩の人は少ないでしょう。倚くの人が「末尟に改行がないテキストファむル」ず呌んでいる事実からも明らかです。

POSIX のテキストファむル関連の甚語の定矩

POSIX の「テキストファむル」ずいう甚語の意味は 3. Definitions で定矩されおいたす。今回の話に関連がある定矩をずりあえず抜粋したす。

3.164 「ファむル」は曞き蟌みたたは読み蟌み、たたはその䞡方が可胜なオブゞェクト

3.164 File
An object that can be written to, or read from, or both. A file has certain attributes, including access permissions and type. File types include regular file, character special file, block special file, FIFO special file, symbolic link, socket, and directory. Other types of files may be supported by the implementation.

3.387 「テキストファむル」は0行以䞊の文字を含むファむル

3.387 Text File
A file that contains characters organized into zero or more lines. The lines do not contain NUL characters and none can exceed {LINE_MAX} bytes in length, including the <newline> character. Although POSIX.1-2024 does not distinguish between text files and binary files (see the ISO C standard), many utilities only produce predictable or meaningful output when operating on text files. The standard utilities that have such restrictions always specify ``text files’’ in their STDIN or INPUT FILES sections.

3.185 「行」は改行で終わる0文字以䞊の文字の䞊び

3.185 Line
A sequence of zero or more non-<newline> characters plus a terminating <newline> character.

3.58 「文字」は文字セットを衚珟する1バむト以䞊の䞊び

3.58 Character
A sequence of one or more bytes representing a member of a character set.

Note: This term corresponds to the ISO C standard term multi-byte character, where a single-byte character is a special case of a multi-byte character. Unlike the usage in the ISO C standard, character here has no necessary relationship with storage space, and byte is used when storage space is discussed. See the definition of the portable character set in Section 6.1 (on page 117) for a further explanation of the graphical representations of (abstract) characters, as opposed to character encodings.

3.61 「文字セット」はデヌタを衚珟するための異なる文字のセット

3.61 Character Set
A finite set of different characters used for the representation, organization, or control of data.

3.63 「文字列」はヌルバむトで終了するヌルバむトを含む文字の䞊び

3.63 Character String
A contiguous sequence of characters terminated by and including the first null byte.

3.172 「䞍完党な行」はファむルの最埌の1文字以䞊の改行ではない文字の䞊び

3.172 Incomplete Line
A sequence of one or more non-<newline> characters at the end of the file.

これだけ箇条曞きにすれば、感がいい人は「あぁ、これは甚語集だ」ず気づいたのではないかず思いたす。

POSIXは「テキストファむル」の芏栌を䜜ったのではない

POSIX にこのように「定矩」されおいるこずから、これがテキストファむルの仕様や芏栌だずよく勘違いされおいたすが、POSIX のテキストファむルの定矩は仕様や芏栌ではありたせん。もし、これが仕様であるならば「shallしなければならない」や「shouldしたほうがよい」のような蚀葉が含たれおいるはずです。これらテキストファむルの定矩には shall も should も䜿われおいたせん。だからこれらは仕様ではないのです。仕様ではないずしたらこれらは䜕なのでしょうか

その答えは、これが曞かれおいるペヌゞのタむトルのずおりです。「3. Definitions」でしたよね そう、これは「POSIX が䜿甚しおいる甚語の定矩」なのです。ペヌゞにトップにはこう曞かれおいたす倪字は私によるもの。

  1. Definitions
    For the purposes of POSIX.1-2024, the following terms and definitions apply. The Authoritative Dictionary of IEEE Standards Terms, Seventh Edition should be referenced for terms not definedin this section.

倪字郚分の蚳: POSIX.1-2024 の目的のために、次の甚語ず定矩が適甚されたす。

Rationale にはこのように曞かれおいたす。

The definitions in this section are stated so that they can be used as exact substitutes for the terms in text. They should not contain requirements or cross-references to sections within POSIX.1-2024; that is accomplished by using an informative note. In addition, the term should not be included in its own definition. Where requirements or descriptions need to be addressed but cannot be included in the definitions, due to not meeting the above criteria, these occur in the General Concepts chapter.

倪字郚分の蚳: このセクションの定矩は、本文䞭の甚語の正確な代替ずしお䜿甚できるように蚘茉されおいたす。補足: 解釈が難しいが残りの郚分には「定矩には芁求事項を含たない」ず曞いおいるように読み取れるので、テキストファむルの定矩には末尟に改行を入れなければならないずいう芁求は含たれおいないず解釈できるかもしれない

POSIX は「甚語の意味を正確に定矩しないず仕様の話ができない」から最初に甚語を定矩しおいたす。それが暙準芏栌の最初の方にある「3. Definitions」です。この段階では仕様の話はただ始たっおいたせん。甚語の定矩だけを芋せられおも「それが POSIX のテキストファむルずいう甚語の定矩であるこずはわかった。それでテキストファむルがどうしたのかね」ず蚀うこずしかできたせん。

POSIX はコマンドの動䜜を正確に説明するために甚語の意味を定矩したのであっお、テキストファむルの仕様や芏栌を決めたのではありたせん。どこぞで「末尟が改行で終わらないファむルもテキストファむルず認めるべきだ」ずいう意芋を芋かけたしたが、それをテキストファむルの定矩にしおしたうずコマンドの動䜜を正確に説明するのが面倒になっおしたいたす。なぜなら「このコマンドはテキストファむルを読み蟌むが、末尟の改行は必須である」ず毎回説明しなければならなくなるからです。

POSIX の甚語の定矩は、POSIX 暙準芏栌で䜿甚するために定矩されたものです。唯䞀の正しい定矩ずいうわけではありたせん。䟋えば蟲林氎産省はむチゎは野菜ず定矩しおいたすが、それは蟲林氎産省の定矩であっお、私たちの䞀般的な定矩ではありたせん。蟲林氎産省の定矩を理由に「むチゎは野菜ず決たっおるんだから野菜コヌナヌに眮け」ずクレヌムを蚀っおいる人がいたずしたら、あなたはこう思うはずです。

お前がそう思うんならそうなんだろう お前ん䞭・・・・ではな (-â–¡ÐŽâ–¡-)

ちなみに米囜ではむチゎは果物ですが、キュりリやナスも果物だそうです。果物もテキストファむルも䞖間䞀般の定矩はさたざたで統䞀されおいたせん。だから仕様ずいう厳密な話をするずきには最初に甚語の正確な意味を定矩をする必芁がありたす。POSIX の甚語の定矩は、POSIX ん䞭の狭い䞖界の定矩でしかなく、POSIX 以倖の䞖間䞀般のテキストファむルの定矩にたで圱響を䞎えるものではありたせん。

テキストファむルの定矩をちゃんず読もう

POSIXの甚語の定矩を匕甚しおいるずころはいく぀もあるのですが、ちゃんず読んでいるず思うこずがよくありたす。POSIX のテキストファむルの定矩を箇条曞するずこうなりたす。

  1. 文字が含たれた 0 行以䞊の行で構成されたファむル空ファむルも含む
  2. 行はヌル文字を含たない
  3. 行は改行を含めお LINE_MAX バむトを超えない
  4. POSIX ではテキストファむルずバむナリファむルを区別しおいない
  5. 倚くのナヌティリティはテキストファむルを操䜜するずきにのみ予枬可胜たたは意味のある出力を生成する
  6. このような制限を持぀暙準ナヌティリティは STDIN たたは INPUT FILES セクションで垞に「テキストファむル」を指定する

これらの項目はすべお重芁です。テキストファむルの末尟に改行が必芁ずいうずころだけを読んで、その他の重芁項目を読み飛ばしおいたせんか

1行が2048バむトを超えたらテキストファむルではない

POSIX のテキストファむルの定矩では 1 行は LINE_MAX バむト以内です。LINE_MAX バむトの倀は環境䟝存です。POSIX ずしおは最䜎 2048 バむトずいうこずになっおおり、Linux、macOS、各BSD Unix、Solaris で調べた所、すべお 2048 バむトでした。したがっお事実䞊 2048 バむトを超える行があったら、そのファむルはテキストファむルではないずいうこずになりたす。

LINE_MAX の調べ方
$ getconf LINE_MAX
2048

2048 バむトは UTF-8 で日本語の 1 文字を 3 バむトず仮定しお蚈算するず 682 文字です。原皿甚玙 1.5 枚分、技術曞だず半ペヌゞ皋床の量です。䞀段萜の目安は倚くおも 300 文字ぐらいが限界なようなので普通のテキスト文曞で問題になるずは思えたせんが、CSV や JSON Lines のような 1 行単䜍で耇数属性のデヌタを持぀ようなテキストベヌスのデヌタ圢匏の堎合は 2048 バむトを超えるこずもあるでしょう。そのような長い行が含たれるファむルは POSIX 的にはテキストファむルではありたせん。しかし「テキストファむルは 1 行の長さを 2048 バむトたでにしろ」ず蚀っおいる人は、なぜだか芋かけたこずがありたせん。

ちなみに LINE_MAX の倀をどうすべきかに぀いおは過去に議論になったようです。その詳现に぀いおは C.1.3 Utility Limits を参照しおください。䞀郚の人々は 1 行の長さに぀いお制限なしを求めたしたが、歎史的なナヌティリティは固定サむズのバッファを䜿甚しおいたため、C 蚀語で固定サむズのバッファの実装を無制限に䜜り倉えるのは倧倉なのでその劥協案ずしお圓時ずしおは倧きめの 2048 バむトが遞ばれたようです。今だずもう少し倧きくおも良かったのではないかず考えるかもしれたせんが、それが決められた 1990 幎頃の性胜が䜎いコンピュヌタでは、小さすぎずメモリ䜿甚量の負担にならない珟実的なサむズだったのでしょう。

LINE_MAX は、各コマンドが䜿甚するバッファのサむズの芁件ではありたせん。぀たりバッファサむズを 2048 バむトにしなければいけないずいう意味ではなく、実際のコマンドはより倚くのサむズを扱えるようにしお構いたせんし、そうするこずが掚奚されおいたす。そのこずもリンク先に明蚘されおいたす。

it may not be a good idea to allocate blindly a buffer for an input line based on the value of {LINE_MAX}, for instance.

LINE_MAX の倀は、POSIX コマンドを䜿甚しお移怍性が高いアプリケヌションシェルスクリプトを曞こうず思っおいるプログラマが、POSIX に準拠しおいるシステムで安心しおコマンドに枡すこずができる 1 行の最倧の長さだずいうこずです。

出力は2048バむト以内にする必芁はない

LINE_MAX は入力時の固定のバッファサむズが由来の制限であるため、出力のサむズには関係したせん。぀たりコマンドの出力は 1 行が 2048 バむトを超えおも構わないずいうこずです。1 行の出力サむズに制限はありたせん。

It should be noted that {LINE_MAX} applies only to input line length; there is no requirement in POSIX.1-2024 that limits the length of output lines.

POSIX では awk、sed、paste コマンドを䟋に、1 行の長さは入力サむズよりも長くなる堎合があり、LINE_MAX を超える行に察凊するのはアプリケヌションシェルスクリプトの責任であるこずが明確に蚘されおいたす。

Utilities such as awk, sed, and paste could theoretically construct lines longer than any of the input lines they received, depending on the options used or the instructions from the application. They are not required to truncate their output to {LINE_MAX}. It is the responsibility of the application to deal with this. If the output of one of those utilities is to be piped into another of the standard utilities, line length restrictions will have to be considered; the fold utility, among others, could be used to ensure that only reasonable line lengths reach utilities or applications.

ここから蚀えるこずは、移怍性が高いシェルスクリプトを曞こうずしおいる人は

sed '...' input.txt | awk '...'
  1. sed コマンドの入力input.txtの 1 行の長さは 2048 バむト以内ですか
  2. awk コマンドの入力の 1 行の長さは 2048 バむト以内ですか

を考慮しなければいけないずいうこずです。たあこんなこず、普通は誰もこんなこず想定したせんよね しかし POSIX を持ち出しお「テキストファむルは POSIX の定矩に埓っお末尟を改行にしなければならない」ず䞻匵するのであれば、同じように「テキストファむルは POSIX の定矩に埓っお 1 行の長さを 2048 バむト以内にしなければならない」ず䞻匵しなければいけないはずです。POSIX に準拠しおシェルスクリプトを曞くずいうのは、こういうこずを考えながらシェルスクリプトを曞くずいうこずです。

GNUコマンドにはサむズ制限はない

おそらくすべおのGNU 版のコマンドの 1 行の長さは、事実䞊の無制限搭茉メモリ量やメモリモデル䞊の制限のみです。このこずは GNU のドキュメントに明蚘されおいたす。

Though grep expects to do the matching on text, it has no limits on input line length other than available memory, and it can match arbitrary characters within a line. If the final byte of an input file is not a newline, grep silently supplies one. Since newline is also a separator for the list of patterns, there is no way to match newline characters in a text.

GNU grep には搭茉メモリ容量以倖の制限はなく、末尟に改行がない堎合は黙っお改行を加える。

For those who want to write portable sed scripts, be aware that some implementations have been known to limit line lengths (for the pattern and hold spaces) to be no more than 4000 bytes. The POSIX standard specifies that conforming sed implementations shall support at least 8192 byte line lengths. GNU sed has no built-in limit on line length; as long as it can malloc() more (virtual) memory, you can feed or construct lines as long as you like.

GNU sed には行の長さによる制限はない。補足: POSIX によるず 8192 バむトは パタヌンスペヌスずホヌルド スペヌスのサむズであり、4000 バむトずは歎史的な実装が䜿甚しおいるサむズなので、GNU による説明は POSIX の説明ず矛盟しおいる

Length of input record in bytes ULONG_MAX

GNU awk には入力行のバむト数の長さに制限はない。その他の制限も事実䞊ない。詳现はリンク先ぞ

If the final byte of an input file is not a newline, GNU sort silently supplies one. GNU sort (as specified for all GNU utilities) has no limit on input line length or restrictions on bytes allowed within lines.

GNU sort は行末に改行がない堎合は黙っお加えるこの動䜜は POSIX でも芏定されおいる。たたすべおの GNU ナヌティリティで指定されおいるように入力行の長さの制限はない

ずいうこずで、GNU コマンドを䜿っおいる限り、行の長さの制限はないようです。詳しく調べおはいたせんがその他の実装も行の長さの制限はない傟向にあるようです。

もちろん制限がないのは GNU コマンドであっお、OS 暙準のコマンドを䜿っお移怍性が高いシェルスクリプトを曞こうず考えおいる人は、サむズ制限を意識する必芁があるでしょう。実際のコマンドに制限があるかどうかは、環境䟝存なので調べるしかありたせん。すべおの環境を調べるずいう面倒なこずをしなくおもいいように POSIX が最䜎のサむズを決めおいたす。しかし、そうやっお POSIX に準拠させようず苊劎しおシェルスクリプトを曞くよりも、どの環境でも動く移怍性が高い GNU コマンドをむンストヌルしおしたったほうが簡単に高い移怍性を実珟するこずができたす。

空ファむルは「テキストファむル」扱いするこずに倉わった

䞭身がないファむルは、はたしお"テキスト"ファむルなのでしょうか 哲孊的な話ですが、POSIX においおは空ファむルもテキストファむルずしお扱うず定矩されおいたす。この定矩は POSIX.1-2008 (Issue 7) で倉曎されおおり、以前は空ファむルはテキストファむルではありたせんでした。

POSIX.1-2001 (Issue 6) たで  テキストファむルは 1 行以䞊

A file that contains characters organized into one or more lines.

POSIX.1-2008 (Issue 7) から  テキストファむルは 0 行以䞊

A file that contains characters organized into zero or more lines.

倉曎の経緯はAustin Group > Aardvark > Aardvark Defect and Bug Reporting > XCU Defect reportsの「Enhancement Request Number 106」で提起されおおり、理由を芁玄するず「diff コマンドで空ファむルをバむナリファむルずしお比范したずきの出力が行われるず困る」「歎史的なコマンドは空ファむルをテキストファむルずしお扱っおきた」の 2 点です。

diff コマンドはバむナリファむルずしお比范した堎合に次のような出力を行いたす。

$ diff data1.txt data2.txt
Binary files data1.txt and data2.txt differ

片方がテキストファむルで、片方がテキストファむル以倖である堎合、diff コマンドはバむナリファむルずしお比范しなければなりたせん。空ファむルをバむナリファむルずしお扱わなければならないのであれば、POSIX に厳密に準拠するず䞊蚘のような出力をしなければならず差分を出力するこずができなくなっおしたいたす。しかし実際の diff コマンドの実装は歎史的にそのような動䜜を行っおおらず空ファむルをテキストファむルず扱っおいたした。

たた、テキストファむルを扱う POSIX コマンドに察しお空ファむルを読み蟌たせるこずができなくなっおしたいたす。䟋えば次のような䟋を考えおみたす。

$ grep "error" /var/log/syslog | sort | uniq

sort コマンドや uniq コマンドはテキストファむルを入力するコマンドです。grep コマンドでログファむルの䞭から error ずいう文字列が含たれる行を抜出したずき、error が芋぀からなければ圓然 grep コマンドは䜕も出力したせん。぀たり空ファむルを出力したす。空ファむルを uniq や sort で凊理しようず思ったずき、もし空ファむルをテキストファむルず認めないのであればコマンドの動䜜は䞍定ずなり、そのような䜿い方は移怍性がないから避けなければならないこずになっおしたいたす。歎史的なコマンドの実装は空ファむルをテキストファむルずしお扱っおきおおり、空ファむルの入力は䞀般的な䜿い方であるため、POSIX はその珟実を正しく暙準化できおいなかったこずになりたす。これがテキストファむルの定矩が倉曎になった理由です。

Enhancement Request Number 106の内容倉曎の経緯
_____________________________________________________________________________
OBJECTION                                       Enhancement Request Number 106
eggert:cs.ucla.edu             Defect in XCU diff (text vs binary) (rdvk#  6)
{20060612a}                             Tue, 13 Jun 2006 06:13:13 +0100 (BST)
_____________________________________________________________________________
Accept_X___    Accept as marked below_____     Duplicate_____     Reject_____
Rationale for rejected or partial changes:

ERN 106 (->interps) AI-192
This needs to be submitted down the interpretations track The standard is clear, standard is wrong, defect, concerns are being forwarded to the sponsors.

_____________________________________________________________________________
Page: 321  Line: 12380  Section: diff


Problem:

Edition of Specification (Year): 2004

Defect code :  1. Error

POSIX says that empty files are not text files, but common practice is to treat empty files as text files.  This causes problems, particularly with "diff", but also with other commands.

1. POSIX's exclusion of empty files from the set of text files requires behavior that contradicts all POSIX implementations that I know of.  For the following script executed in the POSIX locale:

         : > empty
         diff empty empty

POSIX requires that the output of "diff" must contain the word "differ" (see XCU page 321 line 12382).  I know of no diff implementation that does this; they all output nothing, which is what users expect.

2. Typically, diff implementations sample the first few bytes of a file.  If any bytes are zero, they treat the file as binary; otherwise they treat it as text.  In contrast, POSIX requires that "diff" must inspect the entire input file and strictly check for any encoding errors or long lines.

3. POSIX says that portable scripts cannot use standard utilities like 'grep', 'sed,', 'sort', etc. on empty files.  For example, the command:

    grep PATTERN FILE | sort | sed 's/$/./'

does not conform to POSIX if FILE contains no lines that match PATTERN.  Yet this sort of shell script programming is very common practice, and POSIX should not say that the behavior is undefined here.

If there is a good reason that empty files are not text files (compatibility with TENEX, perhaps? :-) then this should be clearly documented in the rationale.  However, I suspect that whatever reason may have existed long ago, is no longer valid.

 Action:

 In XBD page 89 line 2824 (definition of Text File), change from:

   A file that contains characters organized into one or more lines.

 to:

   A file that contains characters organized into zero or more lines.

 In XCU page 321 line 12380-12382 (Diff Binary Output Format), change
 from:

   In the POSIX locale, if one or both of the files being compared are not text files, an unspecified format shall be used that contains the pathnames of two files being compared and the string "differ".

 to:

   In the POSIX locale, if one or both of the files being compared are not text files, it is implementation-defined whether "diff" uses the binary-file output format or the other formats as specified below. The binary-file output format shall contain the pathnames of two files being compared and the string "differ".

 In XRAT page 32 lines 1232-1233, change:

   The definition allows a file with a single <newline>, but not a totally empty file, to be called a text file.

 to:

   The definition allows a file with a single <newline>, or a totally empty file, to be called a text file.

STDINたたはINPUT FILESセクションを読もう

「テキストファむル」の定矩は、単なる甚語の定矩に過ぎたせん。コマンドがどういう動きをするのかずいうコマンドの仕様は、コマンドごずの STDIN たたは INPUT FILES セクションに蚘されおいたす。したがっおテキストファむルの定矩だけを知っおもなんの圹にも立ちたせん。

ちなみにテキストファむルを出力するコマンドは STDOUT や OUTPUT FILES セクションにそのこずが蚘茉されおいたすが、そのようなコマンドはたれです。぀たり倚くのコマンドは POSIX が定矩するテキストファむル以倖を出力する可胜性があるずいうこずです。テキストファむルを出力するず明蚘されおいるのは nl や uuencode がぐらいです。sed コマンドは STDOUT には曞かれおいたせんが、OUTPUT FILES はテキストファむルず曞かれおいたすねこれは間違いのような。

POSIXコマンドの仕様を説明するための「テキストファむル」

POSIX が「テキストファむル」ずいう甚語の意味を定矩した理由は「テキストファむル」ずいう甚語をコマンドの動䜜を説明するために䜿うからです。POSIX コマンド、぀たり歎史的な Unix コマンドの倚くはテキストファむルを扱うコマンドばかりだず考えおいるかもしれたせんが、意倖ずそうではありたせん。入力ファむルずしお任意のファむル圢匏バむナリ圢匏を入力できるず POSIX で芏定されおいるコマンドは結構ありたす。

任意のファむル圢匏を入力できるコマンド

コマンド ファむル圢匏 補足
cat 任意の圢匏
cksum 任意の圢匏
cmp 任意の圢匏
dd 任意の圢匏
diff 任意の圢匏
file 任意の圢匏
od 任意の圢匏
read 任意の圢匏
sh 任意の圢匏 冒頭郚分はシェルが解釈可胜なコヌド
split 任意の圢匏
tee 任意の圢匏
tr 任意の圢匏
wc 任意の圢匏

もちろんテキストファむルしか入力できないコマンドもありたす。その䞀郚には特定のオプションを指定したずきだけ他の圢匏を扱える堎合がありたす。

コマンド ファむル圢匏 補足
awk テキスト
bc テキスト
comm テキスト
csplit テキスト
ed テキスト
expand テキスト
fold テキスト 行の長さに制限なし-b
grep テキスト
iconv テキスト
join テキスト
more テキスト
nl テキスト
sed テキスト
tsort テキスト
tail テキスト 任意の圢匏-c
unexpand テキスト
uniq テキスト
xargs テキスト 任意の圢匏-0

テキストファむルしか入力できないように思えお、䞀郚の制限が緩和されたテキストファむルもどきを扱えるコマンドもありたす。

コマンド ファむル圢匏 補足
cut テキストもどき 行の長さに制限なし
ex テキストもどき 䞍完党な行の堎合は改行を加える
head テキストもどき 行の長さに制限なし、任意の圢匏-c
vi テキストもどき 䞍完党な行の堎合は改行を加える
paste テキストもどき 行の長さに制限なし
sort テキストもどき 䞍完党な行の堎合は改行を加える

「任意の圢匏のファむル」を入力できるコマンド

cat、cksum、cmp、dd、diff、file、od、read、sh、split、tee、tr、wc は任意の圢匏のファむルバむナリファむルを入力できるこずが POSIX で暙準化されおいたす。これは任意の圢匏のファむルを入力した堎合の動䜜が芏定されおいるずいう意味ですが、その動䜜が玍埗できる仕様であるかは別問題です。䟋えば wc コマンドは末尟に改行がないファむルは 1 行少なくカりントされるかのような動䜜を行いたす。

# 末尟に改行があれば 3 行ずカりントする
printf 'FOO\nBAR\nBAZ\n' | wc -l # => 3

# 末尟に改行がなければ 2 行ずカりントする
printf 'FOO\nBAR\nBAZ' | wc -l # => 2

wc コマンドは末尟に改行がない行をカりントしないため、䞀般的には末尟に改行は必ず入れる必芁があるず蚀われおいたす。しかし wc コマンドは単に改行文字の数を数えるだけなので、任意の圢匏のファむルを入力するこずができるずいうのが仕様です。ちなみにこの仕様は POSIX が考案したわけではありたせん。歎史的な wc コマンドの動䜜がそのようになっおおり、移怍性のあるシェルスクリプトを曞きたい人にずっお圹に立぀情報ずいうのは、実際の wc コマンドの正確な動䜜です。

䜙談ですが、POSIX に察しお「wc コマンドの仕様は合理的ではないから倉曎しろ」ず芁求する人がいたす。しかし POSIX が末尟に改行がなくおもカりントしろず曞いたずしおも、誰もそんな仕様で実装しおいないのですから、移怍性のあるシェルスクリプト曞くのに圹に立ちたせん。しかも POSIX はその動䜜に移怍性があるず嘘を曞いおいるこずになりたす。順番を間違えおはいけたせん。たず GNU や BSD ç³» Unix や System V ç³» Unix に蚎えお、実装を倉曎させたあずで改めお POSIX に芁求する必芁がありたす。それが難しいからず蚀っお「POSIX を悪甚しお実際の実装に察しお倉曎するように圧力をかける」こずは蚱されたせん。

cat コマンドにも䌌たような問題がありたす。2぀のテキストファむルがそれぞれ次のような時、

file1.txt
foo
file2.txt
bar<LF>
baz

2 ぀のファむルを結合したずきの出力は次のようになりたす。

$ cat file1.txt file2.txt
foobar
baz             ← 末尟に改行なし

本来、cat コマンドはバむナリファむルを含むファむルを結合するコマンドなので、末尟に改行が含たれおない堎合には、そのたた結合されおしたいたす。

diff コマンドはテキストファむルを比范するだけのように思えたすが、実際にはバむナリファむルを入力するこずができたす。

$ head -c 1000 /dev/urandom > data1.bin
$ head -c 1000 /dev/urandom > data2.bin
$ diff data1.bin data2.bin
Binary files data1.bin and data2.bin differ

read コマンドは POSIX.1-2024 より前たではテキストファむルのみを読み蟌むずいう仕様でした。しかし POSIX.1-2024 ではその仕様が改められ、バむナリファむルやテキストファむルもどきを入力できるようになりたした。その理由の䞀぀は -d オプションの远加により行区切りの文字を䟋えば \0 に倉曎できるようになったからですが、ずっず前おそらく Bourne シェルの時代から、末尟に改行がないテキストファむルもどきを入力するこずができたした。぀たり、以前のPOSIX の暙準化の内容はテキストファむルしか扱えないずいう必芁のない制限があったずいうこずです。

# シェルで実行した cat コマンド盞圓の実装
shcat() {
  # readコマンドは改行を読み取ったら真、読み取らなかったら停ずなる
  while IFS= read -r line; do
    printf '%s\n' "$line"
  done

  # 末尟に改行がないテキストファむルを読み取るこずができる
  # 倉数に末尟に改行がない最終行を読み取っおいる
  printf '%s' "$line"
}

sh コマンドシェルはバむナリファむルを入力するこずができたす。ただし冒頭郚分はシェルが理解できるコヌドでなければなりたせん。぀たりこの仕様はシェルスクリプトの埌半郚分にシェルが実行しないバむナリデヌタを埋め蟌んで利甚するずいうテクニックを犁止しないための仕様です。

tr コマンドはテキストファむルを入力するコマンドのように思えるかもしれたせんが、実際にはデヌタをバむナリずしお凊理するこずができたす。これは入力ファむルに含たれた \0 を削陀したりするために䜿うこずができたす。\0 が含たれたファむルはテキストファむルではありたせん。

$ tr -d '\0' data.bin

「テキストファむル」しか入力できないコマンド

awk、bc、comm、csplit、ed、expand、fold、grep、iconv、join、more、nl、sed、tsort、tail、unexpand、uniq、xargs はテキストファむルしか入力できないずいう制限があるコマンドです。テキストファむル以倖バむナリファむルやテキストファむルもどきを入力した堎合の動䜜は POSIX では芏定されおいないため、最終行の末尟に改行がない堎合に、その行は無芖されおしたっおも文句は蚀えたせん。これらのコマンドのうち fold、tail、xargs は特定のオプションを指定したずきに䞀郚の制限が緩和されたす。

これらのコマンドのうち、特によく䜿うのは awk、grep、sed、tail、uniq、xargs あたりでしょう。これらは POSIX の芏定ではテキストファむルしか入力できないので泚意しおください。これはテキストファむル以倖を入力した堎合の動䜜は移怍性がないずいう意味です。テキストファむルしか入力できないので、移怍性があるシェルスクリプトを開発したいのであれば、入力ファむルの 1 行の長さは 2048 バむト以内にし、末尟には改行を必ず入れる必芁がありたす。

ただし GNU コマンドのような䞀郚の実装では、これらの制限が緩和されおいる堎合がありたす。䟋えば GNU grep は末尟に改行がない堎合に黙っお远加するこずがドキュメントに明蚘されおいたす。Solaris 11 の /bin/grep POSIX 準拠ではないは末尟に改行がない堎合に改行を远加しないようですが、/usr/xpg4/bin/grep POSIX 準拠版远加するようです。AIX 版の grep では末尟に改行がない堎合に远加されるようですが、ドキュメントには「入力ファむルの終わりには、改行文字を付けおください。」ず曞いおあるので、末尟に改行がないファむルを入力するのは避けたほうが良いでしょう。

「テキストファむルもどき」を入力できるコマンド

cut、ex、head、vi、paste、sort はテキストファむルもどき、぀たり POSIX が定めたテキストファむルの条件を満たさないがバむナリファむルよりも制限されたファむルを入力した堎合の動䜜が芏定されおいるコマンドです。

cut、head、paste は 1 行の長さに制限はありたせん。head コマンドは -c オプションを指定したずきに任意の圢匏を扱うこずができたす。head コマンドの察照コマンドずも蚀える tail コマンドには 1 行の長さに制限があるので泚意しおください。head コマンドや tail コマンドのC 蚀語での実装を考えれば、head コマンドに長さの制限を持たせないのは簡単で、tail コマンドは難しいこずが想像できるでしょう。だから実際の実装でこのような制限ができおしたい、移怍性があるシェルスクリプトを開発できるようにするため、その動䜜を POSIX で明文化する必芁がありたした。

ex、vi、sort は䞍完党な行を入力した堎合には末尟に改行を加えるこずが POSIX で暙準化されおいたす。行を䞊び替える sort コマンドは、末尟に改行を加えないず意味のない出力を行っおしたうため、歎史的な実装はどれも末尟に改行を加えたのでしょう。

末尟に改行がないデヌタを

foo<LF>
bar<LF>
baz

末尟に改行を加えずに゜ヌトするず、次のようになっおしたう。

bar<LF>
bazfoo<LF>

ただし Solaris 11 版や AIX 版の sort では改行を加えたずきに譊告が出力されたす。POSIX にはどの OS の話かは曞かれおいたせんが譊告を出力する堎合があるず曞いおあるので、ちゃんず POSIX を読んでいればこの挙動に気づくこずができたす。

$ printf 'FOO\nBAR\nBAZ' | ( PATH=$(getconf PATH); sort )
sort: missing NEWLINE added at end of input file STDIN
BAR
BAZ
FOO

これらのコマンドの存圚は、末尟に改行がないテキストファむルもどきを䜜成するこずを POSIX は犁止しおいない蚌拠でもありたす。もしテキストファむルもどきの䜜成を蚱さないのであれば、単に「入力ファむルはテキストファむルのみである」ずいう仕様にすればよかったはずです。テキストファむルもどきが入力された堎合の動䜜を暙準化しおいるずいうこずは、移怍性がある機胜ずしお䜿甚しお構わないず蚀っおいるのず同じこずです。

diffやGitHubは犁止ではなく譊告しおいる

末尟に改行がないファむルを diff コマンドで比范したずきに「\ No newline at end of file」ず出力されたり、GitHub で「⛔」ず衚瀺されおいるのを芋お、なにか間違ったこずをしたんじゃないかず焊っおいる人がいるようですが、これは単なる譊告です。diff や GitHub が「間違っおいない」ず芪切に教えおくれおいるだけです。末尟に改行がないファむルを犁止しおいるわけではないので、正圓な理由がある堎合は無芖しおも構わないものです。

「\ No newline at end of file」の圹割

diff コマンドでファむルを比范したずきに「\ No newline at end of file」「No newline at end of file」の郚分は翻蚳される可胜性があるず出力されるこずがありたすが、これは末尟に改行がないテキストファむルを䜜っおはいけないずいう意味ではなく、単に末尟に改行がないこずを知らせおいるだけです。もしこの出力がなければ次のようになっおしたい、違いがあるず出力されおいるのに䜕が違うのかわからないこずになっおしたいたす。

$ diff -u file1.txt file2.txt
--- file1.txt   2024-08-03 07:18:01.797900284 +0900
+++ file2.txt   2024-08-03 07:17:57.005895715 +0900
@@ -1,3 +1,3 @@
 foo
 bar
-baz
+baz

「\ No newline at end of file」ずいう出力があるこずで、倉曎前のファむルには行末に改行がなく、倉曎埌のファむルには行末に改行があるずわかりたす。

$ diff -u file1.txt file2.txt
--- file1.txt   2024-08-03 07:18:01.797900284 +0900
+++ file2.txt   2024-08-03 07:17:57.005895715 +0900
@@ -1,3 +1,3 @@
 foo
 bar
-baz
\ No newline at end of file
+baz

diff コマンドの出力結果は、patch コマンドの入力ずしおファむルを倉曎するために䜿甚されおいたす。もし「\ No newline at end of file」ずいう出力がなければ、patch コマンドで末尟の改行を削陀するこずができなくなっおしたいたす。末尟の改行を削陀したいこずはないかもしれたせんが、patch コマンドの圹目ずしおは正しい仕様ずは思えたせん。

実は Solaris 版や AIX 版の diff コマンドは「\ No newline at end of file」を出力する仕様はなく代わりに暙準゚ラヌ出力に譊告が出力される、patch コマンドもこの出力を受け付けたせん。調べたのですがどうやら POSIX では「\ No newline at end of file」の仕様は暙準化されおいないようです。この仕様の発祥がどこかは調べきれたせんでしたおそらく GNU diffですが、BSD ç³» Unix でも広く採甚されおおり、移怍性を高めるために暙準化したほうがよいだろうず私は考えおいたす。

GitHubが「⛔」進入犁止を䜿う理由

GitHub ではテキストファむルの末尟に改行がないずきに「⛔」ずいう絵文字を䜿っお、そのこずを知らせおいたす補足: おそらくファむルタむプ拡匵子を芋おいお .txt の堎合には衚瀺されない。この絵文字は嚁圧感を䞎え、間違っおいるんだから必ず改行を入れろずいうふうに解釈する人がいるようですが、これは「\ No newline at end of file」ず同じで、ただ末尟に改行が含たれおいないず譊告しお知らせおいるだけです。

なぜこれを犁止の意味に捉えおしたうかず蚀うず、絵文字の意味が「進入犁止」だからです。「進入犁止」なのだから、犁止の意味に捉えおしたうのは自然です。しかしこれはただの譊告です。なぜ GitHub はただの譊告に犁止のマヌクを䜿甚しおいるのでしょうか

実は私はある仮説を立おおいたす。䟵入犁止は英語で「DO NOT ENTRY」略しお「NO ENTRY」、たたは「DO NOT ENTER」略しお「NO ENTER」です。知っおの通り ENTER は改行を入力するためのキヌなので「⛔」は「改行なし」ず解釈できないこずもありたせん。「NO ENTER」の甚法は少ないようですが、たったくないずいうわけではないようです。

日本人にずっおは「進入」ず「改行」は結び぀かないので「犁止」のむメヌゞしか残りたせんが、英語では NO ENTER をむメヌゞするのではないでしょうか 「⛔ は NO ENTER」 この蚘事を曞いた理由はこれが蚀いたかったからです。嘘ですが

さいごに

はぁ、やっず前から曞きたかったこの蚘事を曞き䞊げたした。みんな末尟に改行が必芁な理由ずしお、POSIX がヌずか暙準芏栌がヌっお蚀っおるわけですが、みんなそれで玍埗しおるんでしょうか POSIX が蚀っおるこずは結論です。なぜ POSIX がそう蚀っおいるのか、なぜテキストファむルの末尟に改行が必芁なのか、みんなその理由たで考えおいないようです。

それにしおも面倒な話でしょう POSIX に準拠しおシェルスクリプトを曞くべきだなどず安易に蚀う人がいたすが、本圓に POSIX に準拠しお曞くのであれば、1 行の長さ 2048 文字問題ぞの察凊を考える必芁がありたす。はっきり蚀っおそんなこずやっおられたせんよ。制限がないず明確にしおいる GNU コマンドをむンストヌルしたほうが簡単です。このような問題はシェルスクリプト自身の問題ではありたせん。シェルスクリプトの蚀語シェル蚀語自䜓に 1 行の文字列の長さの制限や末尟に改行を入れなければならないずいう芁件はありたせん。これらはコマンドが持぀制限や仕様です。POSIX は珟圚も重芁ですが、それは移怍性のあるアプリケヌションを開発した人にずっおは重芁ずいう意味です。それなのに移怍性のこずを気に必芁がないのに「POSIX がそう決めおいるからそれが正しい」で考えるのをやめる人が倚いように思えたす。

すべおのテキストファむルが末尟に改行が必芁なわけではありたせん。䟋えば JSON ファむルのようにデヌタの終わりが構造から読み取れる堎合には、末尟に改行をいれる必芁はありたせん。ただし、その JSON ファむルの行数を wc コマンドで数えたりするこずが想定されるのであれば、末尟に改行を入れたほうが良いでしょう。倧抵の堎合は末尟に改行を入れおいたほうが安党なので入れるこずを掚奚したすが、テキストファむルの末尟に改行を入れなければいけないかどうかは䜿甚するツヌル次第です。初期の Unix は予算を埗るために文曞線集システムずいう䜓で開発が始たったため、テキスト文曞を扱うコマンドが初期に䜜られたした。POSIX のテキストファむルの定矩がこのようになったのは、耇雑な構造を持぀ JSON などのテキストベヌスのデヌタ構造ではなく倚くの行単䜍のテキスト文曞を扱うコマンドを暙準化する必芁があったからです。

POSIX は POSIX で暙準化しおいるツヌルPOSIX コマンドの動䜜を説明する必芁があるからテキストファむルずいう甚語をあのように定矩しただけで、末尟に改行がないテキストファむルもどきを䜜っおはいけないずは蚀っおいたせん。POSIX コマンドを䜿わない人にずっおは POSIX がなんず蚀っおいたずしおも関係ない話で、自分が䜿うツヌルが末尟に改行がないファむルを期埅したずおりに扱えるかを気にすれば十分です。ただし他の人はそのファむルを POSIX コマンドを䜿っお扱うかもしれないので、特に理由がない限り末尟に改行を入れおおいた方が良いずいうのはそのずおりです。面倒なので省略したしたが、C 蚀語の゜ヌスコヌドも昔は末尟に改行が必芁でしたが、C++ の新しめの芏栌では末尟に改行がなくおも良くなったようです。こういうのも昔の C 蚀語コンパむラの䞀郚には末尟の改行が必須の実装があっったためであり、珟圚の C++ コンパむラの実装は末尟に改行がない堎合に改行を自動的に远加するようになったからなのでしょう。

私が Visual Studio Code はデフォルトで末尟に改行を入れるようにしおおくべきだず思う理由は、どうせ Visual Studio Code なんお高床なテキスト゚ディタを䜿う人はプログラマぐらいでしょずいう考えからです。倚くのプログラマは POSIX コマンドを䜿い移怍性も気にする傟向なので、デフォルトの蚭定をプログラマ向けにしおおけば面倒ではなくなりたす。勝手に末尟に改行が加わり困る自䜓になったずしおもプログラマなら自分でどうにか察凊できるでしょう でも玠人向けのテキスト゚ディタであれば、自分で改行を入れたずきだけ入るほうが盎感的な動䜜かもしれたせん。おそらく Visual Studio Code はデフォルトを玠人向けず定矩し「プログラマなら自分で蚭定を倉曎するこずぐらいできるだろ」ずいう考えなのかもしれたせんね。デフォルトの蚭定はプログラマにずっおは少々䞍䟿ですが、蚭定を倉曎すればいいだけのこずに目くじらを立おる意味がわかりたせん。ちなみに個人的には、ステヌタスバヌに末尟の改行の状態がわかるような衚瀺を加え、保存時に改行を加えるかの蚭定をステヌタスバヌから簡単に倉曎できるようにすればよいのではないかず考えおいたす。

テキストファむルの末尟に改行を入れたほうが良いずいう結論に倉わりはないのですが、この話に POSIX なんお関係ないのですよ。入れたほうが良い理由は単に困る可胜性が高いからです。

22
9
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
22
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?