vi가 파일 끝에 개행 문자(LF)를 자동으로 추가합니까?

vi가 파일 끝에 개행 문자(LF)를 자동으로 추가합니까?

제가 이해할 수 없는 이상한 동작이 있습니다. 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 문자로 구성된 처음 세 줄(숫자 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를 사용하여 두 파일(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를 사용하여 파일이 열었을 때와 여전히 동일한지 확인할 수 있습니다... (예: 여전히 "filename" [마지막 줄 불완전] N 줄, M 문자가 표시됩니다). 저장하면 특정 경고 없이 새 줄이 자동으로 추가됩니다. (얼마나 많은 바이트가 절약되었는지 알려주지만 대부분의 경우 새 줄이 추가되었는지 알기에는 충분하지 않습니다.) vi 메시지를 열었고 실제로 변경 사항이 언제 발생했는지 알 수 있는 방법을 찾는 데 도움이 되었습니다.)

  • 이것은 (자동 수정)POSIX행동! (@barefoot-io 답변 참고)

답변1

POSIX에서는 이 동작이 필요하므로 특이한 점은 없습니다.

~에서POSIX vi 매뉴얼:

입력 파일

vi 명령이 지원하는 입력 파일에 대한 설명은 ex 명령의 입력 파일 섹션을 참조하십시오.

길을 따라가면 도착POSIX 사전 매뉴얼:

입력 파일

입력 파일은 텍스트 파일이거나 텍스트 파일이 될 파일이어야 합니다. 단, 불완전한 마지막 줄은 {LINE_MAX}-1바이트보다 길지 않고 NUL 문자를 포함하지 않습니다. 기본적으로 불완전한 마지막 줄은 뒤에 <newline>이 있는 것으로 처리되어야 합니다. ex 구현에서는 선택적으로 다른 형식의 파일 편집을 허용할 수도 있습니다.

vi 매뉴얼의 출력 파일 섹션도 다음으로 리디렉션됩니다.

결과물 파일

ex의 출력은 텍스트 파일이어야 합니다.

POSIX 정의 쌍:

3.397 텍스트 파일

0개 이상의 줄로 구성된 문자가 포함된 파일입니다. 이 줄에는 NUL 문자가 포함되지 않으며 <newline> 문자를 포함하여 {LINE_MAX}바이트보다 길 수 없습니다. POSIX.1-2008은 텍스트 파일과 바이너리 파일을 구분하지 않지만(ISO C 표준 참조) 많은 유틸리티는 텍스트 파일을 조작할 때 예측 가능하거나 의미 있는 출력만 생성합니다. 이러한 제한이 있는 표준 유틸리티는 항상 STDIN 또는 INPUT FILES 섹션에 "텍스트 파일"을 지정합니다.

3.206라인

0개 이상의 <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가 viSVR3 소스 코드를 기반으로 한다는 의미일 것입니다.

어쨌든 이 동작과 [Incomplete last line]경고 메시지는 적어도 1979년부터 Bill Joy의 레거시 소스 코드에 존재했으며 vi, 내가 아는 한 System V 소스 버전에서 생성되고 특수 빌드가 만들어진 모든 브랜치에 유지됩니다. 일부 Unix(예: AIX).

연대순으로 볼 때 이 동작은 POSIX 준수의 결과라기보다는 Bill Joy가 사용자의 가짜 텍스트 파일 편집을 돕기로 한 초기 결정과 10년 후 이러한 허용 오차를 유지하기로 한 POSIX 위원회의 결정에 따른 결과입니다.

ed대신 사용하면 vi적어도 edSVR3 또는 최신 소스 브랜치에서 오는 경우 전자가 문제에 대해 더 장황하다는 것을 알 수 있습니다.

$ ed file
'\n' appended
8
q

또한 빈 파일은 정확히 0줄을 포함하는 유효한 텍스트 파일입니다. 수정할 종료되지 않은 줄이 없으므로 vi파일을 저장할 때 줄 바꿈이 추가되지 않습니다.

답변3

쉘 루프를 실행할 때 텍스트에서 마지막 줄 바꿈 문자가 잘못 누락되어 while마지막 줄이 자동으로 삭제됩니다.

$ (echo transaction 1; echo -n transaction 2) \
  | while read line; do echo $line; done
transaction 1
$ 

마지막 줄 바꿈이 정확하고 합리적이며 올바른 기본값인지 확인하십시오. 또 다른 옵션은 마지막 줄 바꿈이 누락된 텍스트가 포함된 모든 셸 코드를 이해하고 감사할 시간을 갖는 것입니다. 그렇지 않으면 텍스트의 마지막 줄을 잃을 위험이 있습니다.

답변4

vi파일 끝에 줄바꿈을 추가하는 다른 동작(80년대 중반부터 사용됨)이 기억나지 않습니다 .

~파일이 개행 문자로 끝나지 않는다는 것이 아니라 화면의 행이 텍스트의 일부가 아니라는 것을 나타냅니다 . ( ~셸 스크립트의 마지막 줄에 추가하면 오류를 추적하기 어려울 수 있습니다.) 끝에 줄 바꿈이 있는 짧은 파일을 로드하면 ~텍스트에 줄 바꿈이 아닌 것으로 끝나는 아이디어를 직접 확인하고 반박할 수 있습니다.

관련 정보