이상한 행동을 이해하는 데 어려움이 있습니다 .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 답변 참조)
답변
이것은 예상 된 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
, 당신은 전자는이 문제에 대해 더 자세한 것을 알 수 있습니다 적어도 경우 ed
SVR3 이상 소스 지점에서 IS :
$ ed file
'\n' appended
8
q
빈 파일은 0 줄을 포함하는 유효한 텍스트 파일입니다. 그런 다음 수정해야 할 종료되지 않은 줄 vi
이 없으므로 파일을 저장할 때 줄 바꿈을 추가하지 않습니다.
답변
POSIX에는이 동작이 필요하므로 특별한 방식은 아닙니다.
로부터 POSIX 수동 vi가 :
입력 파일
vi 명령이 지원하는 입력 파일에 대한 설명은 ex 명령의 입력 파일 섹션을 참조하십시오.
받는 사람 흔적에 따라 POSIX 전 설명서 :
입력 파일
입력 파일은 텍스트 파일이거나 길이가 {LINE_MAX} -1 바이트보다 길지 않고 NUL 문자를 포함하지 않는 불완전한 마지막 행을 제외하고 텍스트 파일 인 파일이어야합니다. 기본적으로 불완전한 마지막 줄은 마치 <newline>이있는 것처럼 취급됩니다. 다른 형태의 파일의 편집은 선택적으로 전 구현에 의해 허용 될 수있다.
vi 매뉴얼의 OUTPUT FILES 섹션도 ex로 리디렉션됩니다 :
출력 파일
ex의 출력은 텍스트 파일이어야합니다.
POSIX 정의 쌍 :
0 줄 이상으로 구성된 문자가 포함 된 파일입니다. 행은 NUL 문자를 포함하지 않으며 <newline> 문자를 포함하여 길이가 {LINE_MAX} 바이트를 초과 할 수 없습니다. POSIX.1-2008은 텍스트 파일과 이진 파일을 구분하지 않지만 (ISO C 표준 참조) 많은 유틸리티는 텍스트 파일을 조작 할 때 예측 가능하거나 의미있는 출력 만 생성합니다. 이러한 제한이있는 표준 유틸리티는 항상 STDIN 또는 INPUT FILES 섹션에 “텍스트 파일”을 지정합니다.
0 개 이상의 비 <newline> 문자와 종료 <newline> 문자 순서.
이 매뉴얼 페이지 발췌문의 문맥에서 이러한 정의는 해당 파일의 유일한 변형이 최종 줄 바꿈이없는 경우 해당 ex / vi 구현이 잘못된 텍스트 파일을 허용해야하지만 해당 파일의 버퍼를 작성할 때 결과는 유효한 텍스트 파일이어야한다는 것을 의미합니다.
이 게시물은 POSIX 표준의 2013 년판을 참조했지만 관련 규정은 1997 년판보다 훨씬 더 오래되었습니다 .
마지막으로 ex의 newline appension이 환영받지 못한다면, Seventh Edition UNIX (1979)의 불관용에 의해 심하게 위반 된 느낌이들 것입니다. 매뉴얼에서 :
파일을 읽을 때 ed는 마지막 줄 바꿈 뒤의 ASCII NUL 문자와 모든 문자를 버립니다. 비 ASCII 문자가 포함 된 파일 읽기를 거부합니다.
답변
줄 바꿈이 파일 끝에 추가 된 다른 행동은 기억 나지 않습니다 ( vi
80 년대 중반 이후 사용 ).
은 ~
텍스트의 일부가 아닌 화면에 선이 파일은 줄 바꿈으로 끝나지 않습니다하지 않는 것이 있음을 나타냅니다. ( ~
쉘 스크립트의 마지막 줄에 를 넣으면 오류를 추적하기가 어려워 질 수 있습니다 ). 마지막에 줄 바꿈이있는 짧은 파일을로드하면 ~
자신 을보고 줄 바꿈이 아닌 텍스트를 나타내는 생각을 반증합니다.
답변
쉘 while
루프를 통해 실행되는 최종 개행 문자가 부적절하게 텍스트에 있으면 마지막 행이 자동으로 삭제됩니다.
$ (echo transaction 1; echo -n transaction 2) \
| while read line; do echo $line; done
transaction 1
$
궁극적 인 개행을 보장하는 것이 옳고 제정신이며 적절한 채무 불이행입니다. 다른 옵션은 최종 줄 바꿈이없는 텍스트에 닿는 모든 쉘 코드를 알고 감사 할 시간을 갖거나 텍스트의 마지막 줄을 잃어 버릴 위험이 있습니다.