vi가 파일 끝에 줄 바꿈 (LF)을 자동으로 추가합니까?


36

이상한 행동을 이해하는 데 어려움이 있습니다 .vi 는 파일 끝에 특별히 입력하지 않으면 줄 바꿈 (ASCII : LF, Unix ( AIX ) 시스템 이므로 LF)을 추가하는 것처럼 보입니다 .

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 없음).

그러나 저장하면 39 바이트 대신 40 바이트이며 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 characters) 및 foo2 (39 characters)이 똑같이 나타납니다 ...

그리고 vi에서 foo2 (39 문자, 종료 줄 바꿈 없음)를 열고 아무것도 편집 하지 :wq않고 40 문자를 쓰면 줄 바꿈이 나타납니다!

더 최근의 vi에 접근 할 수 없습니다 (나는 AIX에서 vi, vi ( vim 아님) 버전 3.10이라고 생각합니까?

# strings /usr/bin/vi | grep -i 'version.*[0-9]'
@(#) Version 3.10

vi가 파일의 끝에 줄 바꿈을 자동으로 추가하는 것이 vi입니까? (~는 이전 줄이 줄 바꿈으로 끝나지 않았다고 생각했습니다.)

-

편집 : 아래의 답변 덕분에 추가 업데이트와 약간의 요약이 있습니다.

  • vi 파일이 비어 있지 않은 경우 파일이없는 파일을 쓰는 시점에 후행 줄 바꿈을 자동으로 추가합니다.

  • 그것은 글을 쓸 때만 그렇게합니다! (즉, : w까지 : e를 사용하여 파일을 열었을 때 파일이 여전히 유효한지 확인할 수 있습니다 ... 저장하면 줄 바꿈이 특정 경고없이 자동으로 추가됩니다 (저장 바이트 수를 말하지만 대부분의 경우 줄 바꿈이 추가 된 것을 알기에 충분하지 않습니다) (@jiliagre에게 감사를 표합니다. vi 메시지를 열면 변경이 실제로 발생하는시기를 알 수 있습니다.)

  • 이것은 (자동 수정) POSIX 동작입니다! (참조는 @ barefoot-io 답변 참조)


완전성, AIX 버전 (정식 버전).
EightBitTony

2
나는이 옵션을 가지고있는 AIX의 vi에 대해 모른다. vim-only로
Jeff Schaller

1
@JeffSchaller : 링크에 대한 thx. 불행히도 네이티브 vi에는 ": set noeol"도없고 바이너리 모드로 열 수있는 -b 옵션도 없습니다.
Olivier Dulac

1
명령 vi을 실행하여 버전이나 그 기원에 대한 단서 를 얻을 수 있습니다 :ve.
jlliagre

1
@ThomasDickey 실제로. 어떤 이유로 IBM ex:ver명령이 일반적으로 문서화 된 매뉴얼 페이지를 제거했습니다 .
jlliagre

답변:


28

이것은 예상 된 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]경고 메시지는 vi적어도 1979 년 이후 레거시 Bill Joy의 소스 코드에 있었고 AFAIK는 AIX와 같은 독점 Unix가 빌드 된 System V 소스 코드 릴리스에서 작성된 모든 브랜치에 유지되었습니다.

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

당신이 사용하는 경우 ed대신 vi, 당신은 전자는이 문제에 대해 더 자세한 것을 알 수 있습니다 적어도 경우 edSVR3 이상 소스 지점에서 IS :

$ ed file
'\n' appended
8
q

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


1
나는 vi를 vim으로 잘못 생각한다; 레거시 vi는 이것보다 훨씬 덜 장황하다.
Olivier Dulac

@OlivierDulac 나는 그들을 혼란스럽게하지 않습니다. 이 테스트는 vi다른 유닉스에서도 OP와 마찬가지로 SVR4 레거시를 사용하여 수행되었습니다 . 이것은 아니 vim거나 다른 클론입니다. 이것을 명확히하기 위해 답변이 업데이트되었습니다.
jlliagre

@OlivierDulac 흠, 방금 당신이 실제로 OP라는 것을 알았습니다. AIX가 vi구현을 위해 이전 System V 브랜치를 사용하고있는 것 같습니다 . 아마도 SVR3. [Incomplete last line]파일을 열 때 메시지 가 나타나지 않습니까?
jlliagre

@OlivierDulac이 링크는 AIX vi구현에서 이와 동일한 메시지를 표시 할 수 있음을 나타 냅니다
jlliagre

나는이 내일 보려고 것이다
올리비에 Dulac

51

POSIX에는이 동작이 필요하므로 특별한 방식은 아닙니다.

로부터 POSIX 수동 vi가 :

입력 파일

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

받는 사람 흔적에 따라 POSIX 전 설명서 :

입력 파일

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

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의 newline appension이 환영받지 못한다면, Seventh Edition UNIX (1979)의 불관용에 의해 심하게 위반 된 느낌이들 것입니다. 매뉴얼에서 :

파일을 읽을 때 ed는 마지막 줄 바꿈 뒤의 ASCII NUL 문자와 모든 문자를 버립니다. 비 ASCII 문자가 포함 된 파일 읽기를 거부합니다.


고마워, 그것은 내 질문에 대답합니다. 더 좋은 답변이 나오지 않도록 며칠 더 기다릴 것이지만 지금 당장은 대답이 될 수 있다고 생각합니다.
Olivier Dulac

사양에서 바로 철저하게 문서화 된 답변을 잘 수행하십시오! :)
와일드 카드

1
@Wildcard, 동작은 사양보다 우선합니다.
jlliagre

@jlliagre, Bill Joy의 회고록이나 작성자 ex( 아무도 그의 이름을 모르는)가 없다면 POSIX 사양이 예상대로 좋을 것 같습니다. ;)이 시점에서 "원본 소스"에 가장 가까운 것은 사실이지만 기존 기능에 대한 설명으로 시작되었습니다.
와일드 카드

3
@Wildcard ex는 Bill Joy와 Chuck Alley ( web.cecs.pdx.edu/~kirkenda/joy84.html ) 가 공동으로 작성했습니다 . POSIX 사양에 의문의 여지가 없으며 POSIX 사양에 대한 사실은 현재 vi릴리스가 따르지 않습니다. 오래갑니다.
jlliagre

1

줄 바꿈이 파일 끝에 추가 된 다른 행동은 기억 나지 않습니다 ( vi80 년대 중반 이후 사용 ).

~텍스트의 일부가 아닌 화면에 선이 파일은 줄 바꿈으로 끝나지 않습니다하지 않는 것이 있음을 나타냅니다. ( ~쉘 스크립트의 마지막 줄에 를 넣으면 오류를 추적하기가 어려워 질 수 있습니다 ). 마지막에 줄 바꿈이있는 짧은 파일을로드하면 ~자신 을보고 줄 바꿈이 아닌 텍스트를 나타내는 생각을 반증합니다.


나를 놀라게하는 것은 개행을 추가하는 것입니다 ... vi는 자동으로 추가하지 않을 것으로 기대하지만 그렇게 보입니다 ... 나는이 태도에 대한 설명을 찾고 있습니다 (문제는 사실 : foo2를 열지 않고) 후행 LF)와 그냥 : wq, 그것은 내용을 변경합니다 ... 그래서 그것은 나에게 무언가를 보여 주지만 다른 것을 저장합니다 ... 최소한 말을하면 이상합니다 ^^
Olivier Dulac

선행 ed문자 ()에서 문자를 추가하지 않고 행을 작성하고 편집합니다. 나는 항상 vi를 라인 지향 편집기로 생각했습니다. 그러나 나는 당신의 놀람을 이해합니다.
Anthon

1

while루프를 통해 실행되는 최종 개행 문자가 부적절하게 텍스트에 있으면 마지막 행이 자동으로 삭제됩니다.

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

궁극적 인 개행을 보장하는 것이 옳고 제정신이며 적절한 채무 불이행입니다. 다른 옵션은 최종 줄 바꿈이없는 텍스트에 닿는 모든 쉘 코드를 알고 감사 할 시간을 갖거나 텍스트의 마지막 줄을 잃어 버릴 위험이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.