web-dev-qa-db-ja.com

テキストファイルはなぜ改行で終わるのですか?

私はここにいるすべての人がすべてのテキストファイルが改行で終わるべきであるという格言に精通していると思います。私は何年もの間この「ルール」を知っていましたが、私はいつも疑問に思いました - なぜですか?

1253
Will Robertson

POSIX標準では の定義方法が であるため、

3.206行
0個以上の<newline>以外の文字と末尾の<newline>文字の並び。

したがって、改行文字で終わらない行は実際の行とは見なされません。そのため、プログラムによっては、ファイルの最後の行が改行で終わっていない場合、その最後の行の処理に問題が生じることがあります。

端末エミュレータで作業する場合、このガイドラインには少なくとも1つの難しい利点があります。すべてのUnixツールは、この規約を期待して動作します。たとえば、ファイルをcatと連結する場合、改行で終了するファイルは、次のように指定しない場合とは効果が異なります。

$more a.txt
foo
$more b.txt
bar$more c.txt
baz
$cat {a,b,c}.txt
foo
barbaz

また、前の例でも説明したように、ファイルをコマンドラインに表示するとき(たとえばmoreを介して)、改行で終了するファイルは正しい表示になります。不適切に終了したファイルは文字化けする可能性があります(2行目)。

一貫性を保つために、この規則に従うのは非常に役に立ちます。そうしないと、デフォルトのUnixツールを扱うときに余分な作業が発生します。


別の言い方をします。行が改行で終わらない場合は、catのようなコマンドを使用するのがはるかに難しくなります。

  1. それは各ファイルの開始を新しい行に置きます、それはあなたが95%の時間欲しいものです。しかし
  2. 上の例のように、b.txtc.txtの間で、2つのファイルの最後と最初の行をマージすることができます。

もちろんこれはsolvableですがcatの使い方をもっと複雑にし(位置コマンドライン引数、例えばcat a.txt --no-newline b.txt c.txtなど)、個々のファイルコントロールよりもcommandを使う必要があります他のファイルと一緒に貼り付ける方法これはほぼ確実に便利ではありません。

…あるいは、終止符ではなく継続されると思われる行をマークするために特別なセンチネル文字を導入する必要があります。さて、これでPOSIXと同じ状況で立ち往生していますが、反転していることを除いて(行末文字ではなく行継続)。


さて、POSIX非準拠システム(今日では大部分がWindows)上で重要なのはファイルです。一般にファイルは改行で終わらず、(非公式の)定義はたとえば「text」です。つまり、{区切り文字は改行で囲まれています」(強調に注意してください)。これは完全に有効です。しかしながら、構造化データ(例えばプログラミングコード)の場合、それは解析を最小限にすることをより複雑にします:それは一般的にパーサが書き直されなければならないことを意味します。パーサーがもともとPOSIX定義を念頭に置いて書かれている場合は、パーサーよりもトークン・ストリームを変更する方が簡単な場合があります。つまり、入力の末尾に「人工改行」トークンを追加します。

1187
Konrad Rudolph

各行は最後のものも含めて改行文字で終わらなければなりません。一部のプログラムでは、ファイルの最後の行が改行で終わっていない場合、ファイルの最後の行の処理に問題があります。

GCCは、それがファイルをcannot処理したからではなく、標準の一部としてmust _しているので警告しています。

C言語規格では、空でないソースファイルは改行文字で終わらなければならず、その直後にバックスラッシュ文字を置かないでください。

これは「しなければならない」節なので、この規則に違反したことを示す診断メッセージを出さなければなりません。

これは、ANSI C 1989規格のセクション2.1.1.2にあります。 ISO C 1999規格のセクション5.1.1.2(そしておそらくISO C 1990規格も)。

参照: GCC/GNUメールアーカイブ

261
Bill the Lizard

この回答は、意見ではなく技術的な回答の試みです。

POSIXの純粋主義者になりたい場合、次のように行を定義します。

ゼロ個以上の<newline>以外の文字と、終了する<newline>文字のシーケンス。

ソース: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

次のような不完全な行:

ファイルの最後にある1つ以上の非<newline>文字のシーケンス。

ソース: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

次のようなテキストファイル:

0個以上の行に編成された文字を含むファイル。行にはNUL文字は含まれず、<newline>文字を含めて、長さが{LINE_MAX}バイトを超えることはできません。 POSIX.1-2008はテキストファイルとバイナリファイルを区別しませんが(ISO C標準を参照)、多くのユーティリティは、テキストファイルを操作するときに予測可能または意味のある出力のみを生成します。このような制限がある標準ユーティリティは、STDINまたはINPUT FILESセクションで常に「テキストファイル」を指定します。

ソース: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

次のような文字列:

最初のヌルバイトで終了するバイトの連続したシーケンス。

ソース: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

このことから、ファイルまたはファイルのlineの概念を扱う場合、potentiallyがあらゆるタイプの問題に遭遇するのは、 テキストファイルテキストファイルはゼロ行以上の行で構成されており、わかっている行は<newline>で終了する必要があります)。

適切なケース:wc -l filename

wcのマニュアルから次を読みました。

行は、<newline>文字で区切られた文字列として定義されます。

JavaScript、HTML、CSSファイルがtextファイルであるという意味は何ですか?

ブラウザ、最新のIDE、およびその他のフロントエンドアプリケーションでは、EOFでEOLをスキップしても問題はありません。アプリケーションはファイルを適切に解析します。すべてのオペレーティングシステムがPOSIX標準に準拠しているわけではないため、非OSツール(ブラウザなど)がPOSIX標準(またはOSレベルの標準)に従ってファイルを処理することは実用的ではありません。

その結果、EOFのEOLは、UNIX OSで実行されているかどうかにかかわらず、アプリケーションレベルで実質的に悪影響を及ぼさないと比較的確信できます。

この時点で、クライアント側でJS、HTML、CSSを扱う場合、EOFでEOLをスキップしても安全であると自信を持って言えます。実際、<newline>を含まないこれらのファイルのいずれかを縮小することは安全であると言えます。

これをさらに一歩進めて、NodeJSに関しては、非POSIX準拠環境で実行できるというPOSIX標準に準拠することもできないと言えます。

そのとき何が残っているのでしょうか?システムレベルのツール。

つまり、発生する可能性がある唯一の問題は、POSIXのセマンティクスにその機能を準拠させるための努力をするツールに関するものです(例:wcに示されている行の定義)。

それでも、すべてのシェルが自動的にPOSIXに準拠するわけではありません。たとえば、bashはPOSIXの動作をデフォルトにしません。有効にするスイッチがあります:POSIXLY_CORRECT

EOLの価値が<newline>であると考えるための参考資料: https://www.rfc-editor.org/old/EOLstory.txt

すべての実用的な意図と目的のために、ツールトラックにとどまることを考えてみましょう。

EOLのないファイルで作業してみましょう。これを書いている時点で、この例のファイルはEOLのない縮小されたJavaScriptです。

curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js

$ cat x.js y.js > z.js

-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 x.js
-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 y.js
-rw-r--r--  1 milanadamovsky  15810 Aug 14 23:18 z.js

catファイルサイズは、個々の部分の正確な合計であることに注意してください。 JavaScriptファイルの連結がJSファイルの懸念事項である場合、より適切な懸念事項は、各JavaScriptファイルをセミコロンで開始することです。

このスレッドで他の誰かが言及したように、出力が2つではなく1行になった2つのファイルをcatしたい場合はどうでしょうか。言い換えると、catは、本来行うべきことを実行します。

mancatは、<newline>ではなくEOFまでの読み取り入力のみに言及しています。 cat-nスイッチは、非改行文字(または不完全な行)をline-として出力することにも注意してください。カウントが1で始まること(manによる)

-n 1から始まる出力行に番号を付けます。

POSIXがlineをどのように定義するかを理解したので、この動作はあいまいになり、実際には非準拠になります。

特定のツールの目的とコンプライアンスを理解すると、ファイルをEOLで終了することがどれほど重要かを判断するのに役立ちます。 C、C++、Java(JAR)などでは、いくつかの標準が有効性の改行を指示します-JS、HTML、CSSにはそのような標準は存在しません。

たとえば、wc -l filenameを使用する代わりに、awk '{x++}END{ print x}' filenameを実行できます。また、タスクの成功が、処理しなかったファイル(たとえば、サードパーティのライブラリなど)縮小されたJSとしてcurld)-POSIXに準拠した意味でlinesを数えることを意図していない限り。

結論

JS、HTML、CSSなどの特定のテキストファイルのEOFでEOLをスキップすると、マイナスの影響があるという実際のユースケースはほとんどありません。 <newline>が存在することに依存している場合、ツールの信頼性は、作成し、サードパーティのファイルによって引き起こされる潜在的なエラーにさらされているファイルにのみ制限されます。

ストーリーの教訓:EOFでEOLに依存する弱点のないエンジニアツール。

JS、HTML、CSSに適用されるユースケースは自由に投稿してください。EOLのスキップがどのように悪影響を与えるかを調べることができます。

105
Milan Adamovsky

difference between に関連している可能性があります。

  • テキストファイル(各行は行末で終わることになっています)
  • バイナリファイル(つまり、本当の「行」はなく、ファイルの長さを保持する必要があります)

各行が行末で終わっている場合、たとえば、2つのテキストファイルを連結すると、最初の実行の最後の行が2番目の行の最初の行になることが回避されます。

さらに、エディターはロード時にファイルが行末で終わるかどうかをチェックし、ローカルオプション「eol」に保存して、ファイルの書き込み時にそれを使用できます。

数年前(2005年)、多くの編集者(ZDE、Eclipse、Scite、...)が最終的なEOLを「忘れて」しました これはあまり評価されませんでした
それだけでなく、彼らはその最終EOLを「新しい行を開始する」と誤って解釈し、実際にはすでに存在するかのように別の行を表示し始めます。
上記のエディターのいずれかで開くのに比べて、vimのような正常に動作するテキストエディターを使用した「適切な」テキストファイルでは、これは非常に目立ちました。ファイルの実際の最終行の下に追加の行が表示されました。次のようなものが表示されます。

1 first line
2 middle line
3 last line
4
60
VonC

いくつかのツールはこれを期待しています。たとえば、wcはこれを期待します。

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
40
Flimm

基本的に、最終的なEOL EOFが得られないとファイルを正しく処理できないプログラムがたくさんあります。

GCCはこれについて警告します。C標準の一部として期待されているからです。 (セクション5.1.1.2)

「ファイルの終わりに改行がありません」コンパイラ警告

18
cgp

これは、単純な端末が使用された非常に初期の頃に由来します。改行文字は、転送されたデータの「フラッシュ」を引き起こすために使用されました。

今日、改行文字はもう必要ありません。もちろん、多くのアプリにはまだ改行がなければまだ問題がありますが、私はそれらのアプリのバグだと思います。

しかしながら、あなたが require / newlineというテキストファイルフォーマットを持っているならば、あなたは非常に安い単純なデータ検証を得ます:ファイルが最後に改行を持たない行で終わるなら、あなたはファイルが壊れていることを知っています。 1行に1バイトしか追加されないため、破損したファイルを高精度で検出し、CPU時間をほぼゼロにすることができます。

12
Stefan

上記の実際的な理由に加えて、Unixの発信者(Thompson、Ritchieら)または彼らのMulticsの前任者が、行区切り記号ではなく行末記号を使用する理論的理由があることに気付いても驚きません。ターミネータは、あなたが行のすべての可能なファイルをエンコードすることができます。行区切り文字では、ゼロ行のファイルと1行の空行を含むファイルに違いはありません。両方ともゼロ文字を含むファイルとしてエンコードされています。

その理由は次のとおりです。

  1. それがPOSIXが定義している方法だからです。
  2. いくつかのツールがそれを期待するか、またはそれなしで「誤動作する」ので。たとえば、wc -lは、最後の "line"が改行で終わっていなければカウントしません。
  3. シンプルだから便利だから。 Unixでは、catは正しく動作し、複雑にならずに動作します。解釈する必要なく、各ファイルのバイトをコピーするだけです。 catと同等のDOSはないと思います。 copy a+b cを使用すると、ファイルaの最後の行とファイルbの最初の行がマージされます。
  4. ゼロ行のファイル(またはストリーム)は、1行の空行のファイルと区別できるためです。
11
John Wiersba

別の使用例:あなたのテキストファイルがバージョン管理されているとき(この場合は特にgitの下にありますが他にも当てはまります)。ファイルの末尾にコンテンツが追加されている場合は、最後の行であった行が改行文字を含むように編集されています。これは、その行が最後に編集された日時を見つけるためにファイルをblameするとテキストの追加が表示され、実際に見たいと思う前のコミットではないことを意味します。

10

最後に改行を欠いているファイルに関する実用的なプログラミング問題もあります:read Bash組み込み(私は他のreadの実装については知りません)期待通りに動作しません:

printf $'foo\nbar' | while read line
do
    echo $line
done

これは だけを表示しますfoo!これは、readが最後の行に遭遇すると、その内容を$lineに書き込みますが、EOFに達したため終了コード1を返すためです。これはwhileループを破るので、echo $lineの部分には決して到達しません。この状況に対処したい場合は、次のことを実行する必要があります。

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')

つまり、ファイルの終わりに空でない行があるためにechoが失敗した場合は、readを実行します。当然のことながら、この場合、出力には入力に含まれていなかった余分な改行が1つあります。

10
l0b0

おそらく、単にいくつかの構文解析コードがそれがそこにあると予想していたということです。

私はそれを「ルール」と見なすかどうかは定かではありませんし、それは確かに私が宗教的に固守するものではありません。最も賢明なコードは、テキスト(エンコーディングを含む)を1行ずつ(行末の選択を問わず)、最後の行に改行なしで解析する方法を知っています。

確かに - もしあなたが新しい行で終わったら:EOLとEOFの間に(理論上)空の最終行がありますか?熟考するもの...

9
Marc Gravell

なぜ(テキスト)ファイルは改行で終わらなければならないのですか?

多くの人によく言われるように、

  1. 多くのプログラムはうまく動作しないか、それがないと失敗します。

  2. ファイルをうまく処理するプログラムでさえ'\n'という終わりがない場合でも、このツールの機能はユーザーの期待に沿うものではないかもしれません。

  3. プログラムはめったにない 許可しない 最後の'\n'(私はどれも知らない)。


それでも、これは次の質問を投げかけます:

改行なしのテキストファイルについて、コードは何をすべきですか?

  1. 最も重要 - テキストファイルが改行で終わっていると仮定するコードを書かないでください 仮定 ファイルがフォーマットに準拠していると、データの破損、ハッカーの攻撃、クラッシュが発生します。例:

    // Bad code
    while (fgets(buf, sizeof buf, instream)) {
      // What happens if there is no \n, buf[] is truncated leading to who knows what
      buf[strlen(buf) - 1] = '\0';  // attempt to rid trailing \n
      ...
    }
    
  2. 最後の末尾の'\n'が必要な場合は、ユーザーにその不在と対処を知らせます。さて、ファイルの形式を検証します。注:これには、最大行長、文字エンコードなどに対する制限が含まれる場合があります。

  3. 行方不明の最後の'\n'のコードの取り扱いを文書化して明確に定義します。

  4. できる限り、 生成 末尾の'\n'がないファイルは作成しないでください。

7
chux

私は何年もの間これを自分で思った。しかし、私は今日正当な理由に出会いました。

すべての行にレコードを含むファイルを想像してください(例:CSVファイル)。そして、コンピュータはファイルの最後にレコードを書き込んでいました。しかしそれは突然墜落した。最後の行が完成しましたか。 (悪い状況ではありません)

しかし、もし最後の行をいつも終わらせれば、それでわかるでしょう(単に最後の行が終わっているかどうかチェックしてください)。そうでなければ、おそらく安全のために毎回最後の行を捨てなければならないでしょう。

6
symbiont

ここは非常に遅いですが、ファイル処理のバグに直面したのですが、ファイルが空の改行で終わっていなかったためです。テキストファイルをsedで処理していましたが、sedが出力から最後の行を省略していたため、無効なjson構造が生成され、残りのプロセスが失敗状態になりました。

私たちがしていたのは以下のとおりです。

1つのサンプルファイルsay:foo.txtがあり、その中にいくつかのjsonの内容があります。

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here

ファイルはwidowsマシンで作成され、ウィンドウスクリプトはpowershallコマンドを使用してそのファイルを処理していました。すべて良いです。

sedコマンドを使って同じファイルを処理したときsed 's|value|newValue|g' foo.txt > foo.txt.tmp新しく生成されたファイルは

[{
    someProp: value
},
{
    someProp: value

そしてブーム、それは無効なJSONのために残りのプロセスに失敗しました。

だから、空の改行でファイルを終わらせるのは常に良い習慣です。

3
Arpit

改行なしでファイルを解析するのが困難であった頃からルールが生まれたという印象を常に受け​​ました。つまり、行末がEOL文字またはEOFで定義されているコードを書くことになります。行がEOLで終わっていると仮定する方が簡単でした。

しかし、その規則は改行を必要とするCコンパイラから派生したものだと思います。 「ファイルの終わりに改行がありません」というコンパイラ警告で指摘されているように、 、#includeは改行を追加しません。

3
he_the_great

ファイルがまだ別のプロセスによって生成されている間にファイルが処理されていると想像してください。

それと関係があるのでしょうか。ファイルを処理する準備ができていることを示すフラグ。

0
Pippen_001