
私が理解できない奇妙な動作があります。 viは改行文字(ASCII:LF、Unix(AIX)システム)を特に入力しない場合は、ファイルの末尾に追加します。
viでファイルを編集します(最後に改行文字を入れないように注意してください)。
# vi foo ## Which I will finish on the char "9" and not input a last newline, then `:wq`
123456789
123456789
123456789
123456789
~
~
## When I save, the cursor is just above the last "9", and no newline was added.
私はviがそれを「現状のまま」保存したいので、39バイト:それぞれ10個のASCII文字で構成される最初の3行(数字1〜9、その後に改行文字(私のシステムではLF)が来る)、そして最後の9文字行(改行/ LFを終了せずに文字1〜9)。
しかし、保存するとこんな感じです。40バイト(39の代わりに)とod は LF の終了を示します。:
# wc foo
4 4 40 foo ## I expected 39 here! as I didn't add the last newline
# od -a toto
0000000 1 2 3 4 5 6 7 8 9 lf 1 2 3 4 5 6
0000020 7 8 9 lf 1 2 3 4 5 6 7 8 9 lf 1 2
0000040 3 4 5 6 7 8 9 lf
0000050
## An "lf" terminates the file?? Did vi add it silently?
viと同じように、printfを使用してファイルを生成すると、期待どおりに動作します。
# ## I create a file with NO newline at the end:
# printf "123456789\n123456789\n123456789\n123456789" > foo2
# wc foo2 ## This one is as expected: 39 bytes, exactly as I was trying to do above with vi.
3 4 39 foo ## As expected, as I didn't add the last newline
## Note that for wc, there are only three lines!
## (So wc -l doesn't count lines; it counts the [newline] chars... Which is rather odd.)
# root@SPU0WMY1:~ ## od -a foo2
0000000 1 2 3 4 5 6 7 8 9 lf 1 2 3 4 5 6
0000020 7 8 9 lf 1 2 3 4 5 6 7 8 9 lf 1 2
0000040 3 4 5 6 7 8 9
0000047 ## As expected, no added LF.
viを使用して2つのファイル(foo(40文字)とfoo2(39文字))を再度開くと、まったく同じように見えます。
viでfoo2を開くと(39文字、改行なし):wq
編集せずにやってみてください、40文字を書いて改行が発生したと出ています!
更新されたviにアクセスできません(AIXでこれを実行しています。vi(いいえ)ウィム)バージョン3.10のようですが? (「-version」やそれを知る他の方法はありません))。
# strings /usr/bin/vi | grep -i 'version.*[0-9]'
@(#) Version 3.10
vi(最新バージョンにはありませんか、それともVim?)がファイルの末尾に自動的に改行文字を追加するのが正常ですか? (私の考えでは、〜は前の行が改行文字で終わっていないことを示します。)
-
編集する:次の回答のおかげで、いくつかの追加アップデートといくつかの要約が提供されます。
viは、改行のないファイルを作成すると(ファイルが空でない場合)、自動的に末尾の改行を追加します。
書き込み中にのみこれが行われます! (つまり、:wを使用するまで:eを使用して、ファイルが開かれたときと同じであることを確認できます。保存すると、特定の警告なしに新しい行が自動的に追加されます。ある方法を見つけるのに役立ちました。)
これは(自動修正)POSIXアクション! (@barefoot-ioの回答を参照)
答え1
POSIXではこの動作が必要なので、特別な点はありません。
~からPOSIX vi マニュアル:
入力ファイル
vi コマンドでサポートされている入力ファイルの説明については、ex コマンドの入力ファイルのセクションを参照してください。
道を進むと到着POSIX プリマニュアル:
入力ファイル
入力ファイルはテキストファイルまたはテキストファイルになるファイルでなければなりません。ただし、不完全な最後の行は{LINE_MAX} - 1バイトより長くなく、NUL文字を含みません。デフォルトでは、不完全な最後の行は後ろに<newline>があるものとして扱われるべきです。 ex実装では、オプションで他の形式のファイルを編集することもできます。
vi マニュアルの出力ファイルセクションも次にリダイレクトされます。
結果ファイル
exの出力はテキストファイルでなければなりません。
POSIX定義ペア:
ゼロ行以上の文字を含むファイル。この行には NUL 文字は含まれず、<newline> 文字を含めて {LINE_MAX} バイトより長くすることはできません。 POSIX.1-2008はテキストファイルとバイナリファイルを区別しませんが(ISO C標準を参照)、多くのユーティリティはテキストファイルを操作するときに予測可能または意味のある出力のみを生成します。これらの制限を持つ標準ユーティリティは、常にSTDINまたはINPUT FILESセクションに「テキストファイル」を指定します。
ゼロ個以上の<newline>以外の文字と終了<newline>文字のシーケンス。
これらのマニュアルページの抜粋の文脈では、これらの定義は適切なex / vi実装が間違った形式のテキストファイルを許可する必要がありますが、ファイルの唯一の欠陥が最後の改行文字がない場合は、ファイルのバッファに書き込むときの結果は次のようになります。を意味します。有効なテキストファイルでなければなりません。
この記事はPOSIX標準2013バージョンを参照していますが、関連条項は1997年以前のバージョンでも登場しました。。
最後に、exの改行文字が人気がないことがわかったら、UNIX 7版(1979)に対する不慣れのために深刻に侵害されたと感じるでしょう。マニュアルから:
ファイルを読み取ると、edはASCII NUL文字と最後の改行文字の後のすべての文字を削除します。 ASCII以外の文字を含むファイルの読み取りを拒否します。
答え2
これは予想されるvi
動作です。
ファイルの最後の行は不完全なので、厳密に言えば(つまり、POSIX標準によると)テキストファイルではなくバイナリファイルです。
vi
これはバイナリファイルエディタではなくテキストファイルエディタであり、保存すると正常に修正されます。
これにより、他のテキストファイルツール(wc
などsed
)が予想される出力を提供できます。この問題にはvi
沈黙はありません。
$ printf "one\ntwo" >file # Create a unterminated file
$ cat file # Note the missing newline before the prompt
one
two$ wc -l file # wc ignores the incomplete last line
1 file
$ sed '' file > file1
$ cat file1 # so does a legacy sed
one
$ PATH=$(getconf PATH) sed '' file
one # while a POSIX conformant sed warns you:
sed: Missing newline at end of file file.
two
$ vi file
one
two
~
~
~ # vi tells you too about the issue
"file" [Incomplete last line] 2 lines, 7 characters
:w
"file" 2 lines, 8 characters # and tells it writes two lines
# You'll even notice it writes one more
# character if you are a very shrewd observer :-)
:q
$ cat file # the file is now valid text
one
two
$ wc -l file # wc reports the expected number of lines
2 file
$ sed '' file > file1 # sed works as expected
$ cat file1
one
two
vi
実行中のバージョンの手がかりを取得するには、この:ve
コマンドを使用できます。これは以前のバージョンのSVR4を使用していることを示していますが、これは確かにそうではありませんvim
。
:ve
Version SVR4.0, Solaris 2.5.0
明らかに、あなたの声明は次のとおりです。
:ve
Version 3.10
これは、おそらくAIXがvi
SVR3ソースコードに基づいていることを意味します。
とにかく、この動作と[Incomplete last line]
警告メッセージは少なくとも1979年以来vi
、Bill Joyのレガシーソースコードに存在していました。いくつかのUnix(例:AIX)。
年代順に見ると、この動作は、POSIX準拠の結果ではなく、Bill Joyがユーザーの偽のテキストファイルを編集するのを助ける最初の決定と、10年後にこの許容誤差を維持することにしたPOSIX委員会の決定によるものです。
ed
代わりに、 SVR3または最新のソースブランチからvi
少なくともed
来ると、電子が問題に対してより冗長であることがわかります。
$ ed file
'\n' appended
8
q
また、空のファイルは正確にゼロ行を含む有効なテキストファイルです。変更する終了していない行がないため、vi
ファイルを保存するときに改行は追加されません。
答え3
シェルループを実行すると、テキスト内の最後の改行文字が誤って欠落し、while
最後の行が自動的に削除されます。
$ (echo transaction 1; echo -n transaction 2) \
| while read line; do echo $line; done
transaction 1
$
最後の改行が正しい、合理的で正しいデフォルト値であることを確認してください。別のオプションは、最後の改行がないテキストを含むすべてのシェルコードを理解し、監査する時間を持つことです。そうしないと、テキストの最後の行を失う危険があります。
答え4
vi
ファイルの末尾に改行を追加する他の動作(80年代半ばから使用された)は覚えていません。
~
ファイルが改行文字で終わらないというわけではなく、画面の行がテキストの一部ではないことを示します。 (~
シェルスクリプトの最後の行に追加するとエラーを追跡するのが難しい場合があります)~
。