나는 여기의 모든 사람들이 모든 텍스트 파일이 줄 바꿈으로 끝나야한다는 속담에 익숙하다고 가정합니다. 나는이 "규칙"을 몇 년 동안 알고 있었지만 항상 궁금했습니다. 왜 그렇습니까?
나는 여기의 모든 사람들이 모든 텍스트 파일이 줄 바꿈으로 끝나야한다는 속담에 익숙하다고 가정합니다. 나는이 "규칙"을 몇 년 동안 알고 있었지만 항상 궁금했습니다. 왜 그렇습니까?
답변:
그것이 POSIX 표준이 라인을 정의하는 방식 이기 때문에 :
- 3.206 라인
- 0 개 이상의 비 <newline> 문자와 종료 <newline> 문자 순서.
따라서 개행 문자로 끝나지 않는 행은 실제 행으로 간주되지 않습니다. 따라서 일부 프로그램은 줄 바꿈이 종료되지 않은 경우 파일의 마지막 줄을 처리하는 데 문제가 있습니다.
터미널 에뮬레이터에서 작업 할 때이 지침에 적어도 하나의 장점이 있습니다. 모든 Unix 도구는이 규칙을 기대하고 함께 사용합니다. 예를 들어로 파일을 연결할 때 cat
줄 바꿈으로 끝나는 파일은 다음이없는 파일과 다른 효과를 갖습니다.
$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz
그리고 이전 예제에서도 보여 주듯이, 명령 줄에 파일을 표시 할 때 (예 :를 통해 more
) 줄 바꿈으로 끝나는 파일이 올바르게 표시됩니다. 잘못 종료 된 파일이 깨졌을 수 있습니다 (두 번째 줄).
일관성을 유지하려면이 규칙을 따르는 것이 매우 유용합니다. 그렇지 않으면 기본 Unix 도구를 다룰 때 추가 작업이 필요합니다.
다르게 생각하십시오 : 줄 바꿈으로 줄이 끝나지 않으면 cat
유용한 명령을 만드는 것이 훨씬 어렵습니다. 파일을 연결하는 명령을 만드는 방법
b.txt
와 c.txt
? 사이에서 두 파일의 마지막 줄과 첫 줄을 병합 할 수 있습니다 .물론이는 풀 수 있지만의 사용 확인해야합니다 cat
(위치 명령 행 인수, 예를 추가하여 더 복잡한을 cat a.txt --no-newline b.txt c.txt
지금), 및 명령 보다는 다른 파일과 함께 붙여 넣기하는 방법을 각 개별 파일을 제어합니다. 이것은 거의 확실하지 않습니다.
… 또는 종료하지 않고 계속되는 줄을 표시하려면 특수한 센티넬 문자를 도입해야합니다. 글쎄, 이제 당신은 역행을 제외하고 POSIX와 같은 상황에 갇혀 있습니다 (행 종료 문자가 아닌 행 연속 문자).
자, 비 POSIX 호환 시스템 (요즘의 대부분의 Windows 것을), 요점은 논쟁은 다음과 같습니다 파일은 일반적으로 줄 바꿈으로 끝나지 않고, 예를 들어 줄 힘의 (비공식) 정의는 "있는 텍스트 여야 분리 줄 바꿈에 의해" (강조 표시). 이것은 전적으로 유효합니다. 그러나 구조화 된 데이터 (예 : 프로그래밍 코드)의 경우 구문 분석이 최소로 복잡해집니다. 일반적으로 구문 분석기를 다시 작성해야합니다. 파서가 원래 POSIX 정의를 염두에두고 작성된 경우 파서보다는 토큰 스트림을 수정하는 것이 더 쉬울 수 있습니다. 즉, 입력의 끝에 "인공 줄 바꿈"토큰을 추가하십시오.
cat
유용하고 일관된 방식 으로 도구를 작성하는 것을 훨씬 어렵게 만듭니다 .
각 줄은 마지막 줄을 포함하여 줄 바꿈 문자로 끝나야합니다. 줄 바꿈이 끝나지 않은 파일의 마지막 줄을 처리하는 데 문제가있는 프로그램이 있습니다.
GCC는 파일을 처리 할 수 없기 때문에 가 아니라 표준의 일부로 해야 하기 때문에 경고 합니다.
C 언어 표준에 따르면 비어 있지 않은 소스 파일은 줄 바꿈 문자로 끝나고 백 슬래시 문자 바로 앞에 오지 않아야합니다.
이것은 "shall"절이므로이 규칙을 위반하면 진단 메시지를 보내야합니다.
이것은 ANSI C 1989 표준의 2.1.1.2 섹션에 있습니다. ISO C 1999 표준 (그리고 아마도 ISO C 1990 표준)의 5.1.1.2 절.
참조 : GCC / GNU 메일 아카이브 .
wc -l
는 줄 바꿈이 끝나지 않은 파일의 마지막 줄을 계산하지 않습니다. 또한 cat
첫 번째 파일의 마지막 줄이 줄 바꿈이 아닌 경우 파일의 마지막 줄을 다음 파일의 첫 줄과 하나로 연결합니다. 구분 기호로 줄 바꿈을 찾는 거의 모든 프로그램이 이것을 망칠 가능성이 있습니다.
cat
과 wc
)?
이 답변은 의견이 아닌 기술적 답변을 시도한 것입니다.
POSIX 순수 주의자가 되려면 다음과 같이 라인을 정의하십시오.
0 개 이상의 비 <newline> 문자와 종료 <newline> 문자 순서.
출처: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
불완전한 라인 :
파일 끝에서 하나 이상의 비 <newline> 문자 시퀀스.
출처: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
다음과 같은 텍스트 파일 :
0 개 이상의 줄로 구성된 문자가 포함 된 파일입니다. 행은 NUL 문자를 포함하지 않으며 <newline> 문자를 포함하여 길이가 {LINE_MAX} 바이트를 초과 할 수 없습니다. POSIX.1-2008은 텍스트 파일과 이진 파일을 구분하지 않지만 (ISO C 표준 참조) 많은 유틸리티는 텍스트 파일에서 작업 할 때 예측 가능하거나 의미있는 출력 만 생성합니다. 이러한 제한이있는 표준 유틸리티는 항상 STDIN 또는 INPUT FILES 섹션에 "텍스트 파일"을 지정합니다.
출처: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
다음과 같은 문자열 :
첫 번째 null 바이트로 끝나고 포함 된 연속적인 바이트 시퀀스입니다.
출처: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
이로부터 우리는 잠재적으로 어떤 유형의 문제가 발생할 수 있는 유일한 시간 은 파일 의 줄 또는 파일 의 개념을 텍스트 파일 로서 텍스트 파일 ( 텍스트 파일 이 0으로 구성 되어 있다는 것)을 다룰 때 뿐이라는 것을 알 수 있습니다 또는 그 이상의 줄과 우리가 알고있는 줄은 <newline>으로 끝나야합니다).
적절한 사례 : wc -l filename
.
에서 wc
의 사용 설명서 우리는 읽기 :
줄은 <newline> 문자로 구분 된 문자열로 정의됩니다.
JavaScript, HTML 및 CSS 파일이 텍스트 파일 이라는 의미는 무엇입니까 ?
브라우저, 최신 IDE 및 기타 프런트 엔드 응용 프로그램에서는 EOF에서 EOL을 건너 뛰는 데 문제가 없습니다. 응용 프로그램은 파일을 올바르게 구문 분석합니다. 모든 운영 체제가 POSIX 표준을 준수하는 것은 아니므로, OS 이외의 도구 (예 : 브라우저)가 POSIX 표준 (또는 OS 레벨 표준)에 따라 파일을 처리하는 것은 비현실적입니다.
결과적으로 EOF의 EOL이 UNIX OS에서 실행되는지 여부에 관계없이 EOF의 EOL이 애플리케이션 레벨에서 사실상 부정적인 영향을 미치지 않을 것이라고 확신 할 수 있습니다.
이 시점에서 클라이언트 측에서 JS, HTML, CSS를 다룰 때 EOF에서 EOL을 건너 뛰는 것이 안전하다고 확신 할 수 있습니다. 실제로 <newline>을 포함하지 않는 이러한 파일 중 하나를 축소하는 것이 안전하다고 말할 수 있습니다.
이 단계를 한 단계 더 나아가서 NodeJS에 관한 한 POSIX 표준을 준수 할 수 없다는 점은 POSIX를 준수하지 않는 환경에서 실행할 수 있다는 것입니다.
그때 우리는 무엇을 남겼습니까? 시스템 레벨 툴링.
이는 POSIX의 의미에 기능을 적용하기 위해 노력하는 도구 (예 :에 표시된대로 줄 정의)와 관련하여 발생할 수있는 유일한 문제입니다 wc
.
그럼에도 불구하고 모든 쉘이 POSIX를 자동으로 준수하지는 않습니다. 예를 들어 Bash는 기본적으로 POSIX 동작으로 설정되지 않습니다. 그것을 가능하게하는 스위치가 있습니다 : POSIXLY_CORRECT
.
EOL의 가치에 대한 생각은 <newline>입니다 : https://www.rfc-editor.org/old/EOLstory.txt
모든 실용적인 의도와 목적을 위해 툴링 트랙에 머물면서 다음을 고려하십시오.
EOL이없는 파일로 작업 해 봅시다. 이 글을 쓰는 시점에서이 예제의 파일은 EOL이없는 축소 된 JavaScript입니다.
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js
$ cat x.js y.js > z.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 x.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 y.js
-rw-r--r-- 1 milanadamovsky 15810 Aug 14 23:18 z.js
통지 cat
파일 크기가 정확히 개별 부품의 합계입니다. JavaScript 파일의 연결이 JS 파일의 문제인 경우, 각 JavaScript 파일을 세미콜론으로 시작하는 것이 더 적절한 문제입니다.
이 스레드에서 다른 사람이 언급했듯이 cat
출력이 두 줄이 아닌 한 줄이되는 두 파일 을 원한다면 어떻게해야 합니까? 즉, cat
해야 할 일을합니다.
는 <newline>이 아니라 EOF까지 입력을 읽는 man
것에 cat
대해서만 언급합니다. 주의가 있는지 -n
의 스위치는 cat
또한 비 <개행> 종료 행 (또는 출력한다 불완전한 라인 A와) 라인 - 인을 카운트에서 시작하는 1 단계 (받는 항 man
).
-n 1부터 시작하여 출력 라인의 번호를 지정합니다.
POSIX가 어떻게 라인을 정의하는지 이해 했으므로 ,이 동작은 모호하거나 실제로 비 호환이됩니다.
주어진 도구의 목적과 규정을 이해하면 EOL로 파일을 종료하는 것이 얼마나 중요한지를 결정하는 데 도움이됩니다. C, C ++, Java (JARs) 등에서 일부 표준은 유효성에 대한 줄 바꿈을 지시합니다 .JS, HTML, CSS에 대한 표준은 없습니다.
예를 들어, wc -l filename
하나 를 사용하는 대신 할 수 awk '{x++}END{ print x}' filename
있고 작업의 성공이 우리가 작성하지 않은 처리하려는 파일 (예 : 축소 된 JS와 같은 타사 라이브러리)에 의해 위험에 처하지 않음을 확신 curl
하십시오. 의도는 진정으로 줄 을 세는 것이 었습니다 POSIX 호환 의미에서 .
결론
JS, HTML 및 CSS와 같은 특정 텍스트 파일에 대해 EOF에서 EOL을 건너 뛰는 것이 실제로 부정적인 영향을 미치는 실제 사용 사례는 거의 없습니다. <newline>을 사용하는 경우 툴링의 신뢰성을 우리가 작성하는 파일로만 제한하고 타사 파일에서 발생한 잠재적 오류까지 열 수 있습니다.
이야기의 교훈 : EOF에서 EOL에 의존하는 약점이없는 툴링 엔지니어.
EOL을 건너 뛰는 것이 어떻게 악영향을 미치는지 검토 할 수있는 사용 사례를 JS, HTML 및 CSS에 적용 할 때 자유롭게 게시하십시오.
다음의 차이점 과 관련이있을 수 있습니다 .
각 줄이 줄 끝으로 끝나는 경우 예를 들어 두 개의 텍스트 파일을 연결하면 첫 번째 줄의 마지막 줄이 두 번째 줄의 첫 줄로 바뀌지 않습니다.
또한 편집기는 파일이 줄 끝으로 끝나는 지 여부를로드에서 확인하고 파일을 로컬 옵션 'eol'에 저장 한 후 파일을 쓸 때이를 사용할 수 있습니다.
몇 년 최종 EOL, "잊지"는 않았다 (2005) 많은 편집자 (ZDE, 이클립스, Scite를, ...) 백업 매우 평가되지 않았습니다 .
뿐만 아니라 최종 EOL을 '새 줄 시작'으로 잘못 해석하고 실제로 다른 줄이 이미 존재하는 것처럼 표시하기 시작합니다.
위의 편집기 중 하나에서 파일을 여는 것과 비교할 때 vim과 같이 잘 작동하는 텍스트 편집기가있는 '적절한'텍스트 파일에서 매우 잘 보입니다. 파일의 실제 마지막 줄 아래에 여분의 줄이 표시되었습니다. 다음과 같은 것이 보입니다 :
1 first line
2 middle line
3 last line
4
일부 도구는 이것을 기대합니다. 예를 들어 다음과 같이 wc
예상됩니다.
$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
wc
하지 않을 수도 있습니다.
wc -l
를 인쇄 1
하는 것이지만 일부 사람들은 두 번째 경우를 인쇄해야한다고 말할 수 있습니다 2
.
\n
POSIX / UNIX와 같이 줄 구분 기호가 아닌 줄 종결 자로 생각 하면 2를 인쇄하는 두 번째 경우를 기대하는 것은 절대적으로 미칩니다.
기본적으로 최종 EOL EOF를 얻지 못하면 파일을 올바르게 처리하지 못하는 많은 프로그램이 있습니다.
GCC는 C 표준의 일부로 예상되므로 이에 대해 경고합니다. (섹션 5.1.1.2)
이것은 단순한 터미널이 사용 된 초기부터 시작되었습니다. 개행 문자는 전송 된 데이터의 '플러시'를 트리거하는 데 사용되었습니다.
오늘날 개행 문자는 더 이상 필요하지 않습니다. 물론 개행이 없으면 많은 앱에 여전히 문제가 있지만 해당 앱의 버그로 간주합니다.
그러나 줄 바꿈 이 필요한 텍스트 파일 형식이 있으면 간단한 데이터 확인이 매우 저렴합니다. 파일 끝에 줄 바꿈이없는 줄로 파일이 끝나면 파일이 손상되었음을 알 수 있습니다. 각 줄에 하나의 추가 바이트 만 있으면 CPU 시간없이 거의 정확하게 깨진 파일을 감지 할 수 있습니다.
별도의 유스 케이스 : 텍스트 파일이 버전 제어되는 경우 (이 경우 특히 git에서 다른 파일에도 적용됨). 내용이 파일 끝에 추가되면 이전 줄의 마지막 줄이 줄 바꿈 문자를 포함하도록 편집됩니다. 즉, blame
해당 행이 마지막으로 편집 된 시간을 찾기 위해 파일을 열면 실제로보고자하는 커밋이 아니라 텍스트 추가가 표시됩니다.
\n
)가 아닌 "new lines"을 탐지하도록 업데이트되어야합니다 . 문제 해결됨.
위의 실제적인 이유 외에도 Unix (Thompson, Ritchie 등) 또는 Multics의 선임자들이 줄 구분 기호보다 줄 종결자를 사용하는 이론적 인 이유가 있음을 깨달았을 때 놀라지 않을 것입니다. 터미네이터를 사용하면 가능한 모든 행 파일을 인코딩 할 수 있습니다. 줄 구분 기호를 사용하면 줄이 0 인 파일과 빈 줄이 하나 포함 된 파일간에 차이가 없습니다. 둘 다 0 문자를 포함하는 파일로 인코딩됩니다.
따라서 그 이유는 다음과 같습니다.
wc -l
줄 바꿈으로 끝나지 않으면 최종 "줄"을 계산하지 않습니다.cat
제대로 작동하며 합병증없이 작동합니다. 해석 할 필요없이 각 파일의 바이트 만 복사합니다. 에 해당하는 DOS가 있다고 생각하지 않습니다 cat
. 를 사용 copy a+b c
하면 파일의 마지막 줄이 파일 a
의 첫 줄과 병합 됩니다.b
.아마도 일부 파싱 코드가 거기에있을 것으로 예상했을 것입니다.
나는 그것이 "규칙"으로 간주 될지 확신하지 못하며, 확실히 내가 종교적으로 고수하는 것이 아니다. 대부분의 현명한 코드는 마지막 줄에서 줄 바꿈없이 또는 줄 바꿈없이 텍스트 (인코딩 포함)를 한 줄씩 (줄 끝 선택) 구문 분석하는 방법을 알고 있습니다.
실제로-새로운 줄로 끝나는 경우 : 이론적으로 EOL과 EOF 사이에 빈 마지막 줄이 있습니까? 하나는 숙고 ...
마지막에는 줄 바꿈이없는 파일에 대한 실제 프로그래밍 문제가 있습니다 read
.Bash 내장 (다른 read
구현에 대해서는 모른다 )이 예상대로 작동하지 않습니다.
printf $'foo\nbar' | while read line
do
echo $line
done
이 인쇄 만foo
! 그 이유는 read
마지막 줄을 만나면 내용을 $line
쓰지만 EOF에 도달했기 때문에 종료 코드 1을 반환하기 때문입니다. 이로 인해 while
루프 가 끊어 지므로 echo $line
부품에 도달하지 못합니다 . 이 상황을 처리하려면 다음을 수행해야합니다.
while read line || [ -n "${line-}" ]
do
echo $line
done < <(printf $'foo\nbar')
즉, 파일 끝에서 비어 있지 않은 행으로 인해 실패한 echo
경우 수행 read
하십시오. 당연히이 경우 출력에 입력에없는 새로운 줄 바꿈이 하나 더 생깁니다.
(텍스트) 파일이 줄 바꿈으로 끝나야하는 이유는 무엇입니까?
많은 사람들이 잘 표현한 이유는 다음과 같습니다.
많은 프로그램이 제대로 작동하지 않거나 실패하면 실패합니다.
파일을 잘 처리하는 프로그램에도 결말이 없기 때문에 '\n'
도구의 기능은 사용자의 기대에 미치지 못할 수 있습니다.이 경우에는 분명하지 않습니다.
프로그램은 거의 최종적인 것을 허용'\n'
하지 않습니다 (아무도 모르겠습니다).
그러나 이것은 다음 질문을 제기합니다.
줄 바꿈없이 텍스트 파일에 대해 코드는 어떻게해야합니까?
가장 중요- 텍스트 파일이 줄 바꿈으로 끝나는 것으로 가정하는 코드를 작성하지 마십시오 . 파일이 형식을 준수 한다고 가정하면 데이터 손상, 해커 공격 및 충돌이 발생합니다. 예:
// Bad code
while (fgets(buf, sizeof buf, instream)) {
// What happens if there is no \n, buf[] is truncated leading to who knows what
buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing \n
...
}
마지막 후행 '\n'
이 필요한 경우 사용자에게 부재와 조치를 알려줍니다. 파일 형식을 확인하십시오. 참고 : 여기에는 최대 줄 길이, 문자 인코딩 등에 대한 제한이 포함될 수 있습니다.
결측 된 final 처리하는 코드 처리를 명확하게 정의하십시오 '\n'
.
가능한 결말이없는 파일을 생성 하지 마십시오 '\n'
.
여기는 매우 늦었지만 파일 처리에서 하나의 버그에 직면했으며 파일이 빈 줄 바꿈으로 끝나지 않기 때문에 발생했습니다. 우리는 텍스트 파일을 처리하고 sed
있었고sed
있었고 출력에서 마지막 줄을 생략하여 유효하지 않은 json 구조를 일으키고 나머지 프로세스를 실패 상태로 보냈습니다.
우리가하고있는 일은 :
하나의 샘플 파일이 있습니다 : foo.txt
그 json
안에 내용이 있습니다.
[{
someProp: value
},
{
someProp: value
}] <-- No newline here
파일은 미망인 컴퓨터에서 생성되었으며 창 스크립트는 PowerShell 명령을 사용하여 해당 파일을 처리했습니다. 문제 없다.
sed
명령을 사용하여 동일한 파일을 처리했을 때sed 's|value|newValue|g' foo.txt > foo.txt.tmp
새로 생성 된 파일은
[{
someProp: value
},
{
someProp: value
붐은 잘못된 JSON으로 인해 나머지 프로세스에 실패했습니다.
따라서 항상 빈 줄 바꿈으로 파일을 끝내는 것이 좋습니다.
나는 항상 줄 바꿈없이 파일을 파싱하는 것이 어려웠던 시절부터 규칙이 왔다는 인상을 받았다. 즉, EOL 문자 또는 EOF로 행 끝을 정의한 코드를 작성하게됩니다. EOL로 끝나는 라인을 가정하는 것이 더 간단했습니다.
그러나 나는 규칙이 개행을 요구하는 C 컴파일러에서 파생되었다고 생각합니다. "파일 끝에 줄 바꿈 없음"컴파일러 경고에서 지적한 것처럼 #include는 줄 바꿈을 추가하지 않습니다.
IMHO, 그것은 개인적인 스타일과 의견의 문제입니다.
옛날에는 그 개행을 넣지 않았습니다. 저장된 문자는 14.4K 모뎀을 통해 더 빠른 속도를 의미합니다.
나중에 Shift + 아래쪽 화살표를 사용하여 최종 줄을 쉽게 선택할 수 있도록 줄 바꿈을 넣었습니다.