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만 남음 줄(문자 1~9, 줄 바꿈/LF 종료 없음).

그런데 저장하면 이렇게 나오네요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 명령의 INPUT FILES 섹션을 참조하십시오.

트레일을 따라가면POSIX ex 매뉴얼:

입력 파일

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

vi 매뉴얼의 OUTPUT FILES 섹션도 ex로 리디렉션됩니다.

출력 파일

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 소스 코드를 기반으로 한다는 의미일 가능성이 높습니다.

어쨌든 이 동작과 경고 메시지는 최소한 1979년부터 [Incomplete last line]레거시 Bill Joy의 소스 코드에 있었고 AFAIK는 AIX와 같은 독점 Unix가 빌드된 System V 소스 코드 릴리스에서 생성된 모든 분기에 유지되었습니다.vi

연대순으로 말하면 이 동작은 POSIX 준수의 결과가 아니라 사용자가 가짜 텍스트 파일을 편집하는 데 도움이 되겠다는 Bill Joy의 원래 결정과 10년 후 POSIX 위원회가 이러한 허용 오차를 유지하기로 결정한 결과입니다.

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

$ 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

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

~화면에 텍스트의 일부가 아닌 행이 있다는 것을 의미하며 파일이 개행 문자로 끝나지 않는다는 의미는 아닙니다. ( ~셸 스크립트의 마지막 줄에 를 넣으면 오류를 추적하기 어려울 수 있습니다 .) 끝에 개행 문자가 있는 짧은 파일을 로드하면 ~자신을 보게 될 것이며 그것이 개행 문자로 끝나지 않는 텍스트를 나타낸다고 생각했다는 것을 반증하게 될 것입니다.

관련 정보