Không có dòng mới ở cuối tệp


472

Khi thực hiện, git diffnó nói "Không có dòng mới ở cuối tập tin" .

Ok, không có dòng mới ở cuối tập tin. Vấn đề lớn là gì?

Tầm quan trọng của thông điệp là gì và nó đang cố nói gì với chúng tôi?


11
Có lẽ, nếu bạn có một tệp kết thúc mà không có dòng mới và bạn thêm một dòng khác, git sẽ phải chỉ ra rằng dòng cuối cùng trước đó đã thay đổi, vì nó bao gồm ký tự dòng mới là một phần của dòng?
nafg

Câu trả lời:


458

Nó cho biết rằng bạn không có dòng mới (thường '\n'là CR hoặc CRLF) ở cuối tệp.

Nghĩa là, nói một cách đơn giản, byte cuối cùng (hoặc byte nếu bạn có trên Windows) trong tệp không phải là một dòng mới.

Thông báo được hiển thị bởi vì nếu không, không có cách nào để phân biệt sự khác biệt giữa một tệp có dòng mới ở cuối và một nơi không có. Diff phải xuất ra một dòng mới, hoặc kết quả sẽ khó đọc hoặc xử lý tự động hơn.

Lưu ý rằng đó là một phong cách tốt để luôn đặt dòng mới là ký tự cuối cùng nếu nó được định dạng tệp cho phép. Hơn nữa, ví dụ, đối với các tệp tiêu đề C và C ++, nó được yêu cầu bởi tiêu chuẩn ngôn ngữ.


136
Vì tò mò, bạn có thể giải thích tại sao nó được coi là phong cách tốt để luôn đặt một dòng mới là nhân vật cuối cùng không? Chỉnh sửa: tìm thấy cuộc thảo luận này .
Paul Bellora

84
@PaulBellora Trong lịch sử, đó là một quyết định được đưa ra bởi stackoverflow tiêu chuẩn ngôn ngữ C.com/a/729725/233098 Thực tế, bởi vì nhiều công cụ Unix yêu cầu hoặc mong đợi nó để hiển thị stackoverflow.com/a/729795/233098 . Về mặt triết học, bởi vì mỗi dòng trong tệp văn bản kết thúc bằng ký tự "cuối dòng" - dòng cuối cùng không nên là ngoại lệ. Suy nghĩ về nó khác đi, hãy khám phá điều ngược lại. Nếu có một điểm đánh dấu "bắt đầu của dòng" thay vì "cuối dòng", bạn có bỏ qua ký tự "bắt đầu của dòng" trên dòng đầu tiên không?
Joe

29
@Joe Điều đó không có ý nghĩa nhiều lắm. Một dòng mới là một dòng mới , tức là dấu phân cách giữa các dòng, không phải là dòng cuối. Chúng tôi không bắt đầu các ký tự dòng vì chúng không cần thiết. Chúng tôi không có kết thúc của các ký tự cho cùng một lý do.
acjay

6
@acjay Tôi lập luận rằng vốn dĩ đã tốt hơn giữa "Dấu phân cách giữa các dòng" so với "cuối dòng". Không phải cái nhìn vốn dĩ là đúng hay sai, chỉ là một cách để nhìn vào nó. Tôi đề nghị chúng ta nên tiếp tục sử dụng quan điểm lịch sử thực tế, vì chúng ta đã làm theo cách đó và nó ý nghĩa khi bạn chấp nhận nó. Tính nhất quán là quan trọng. Không cần phải phá vỡ điều đó trong tên của quan điểm "dấu phân cách giữa các dòng".
Joe

17
@WORMSS "Mới đối với tôi" không giống với "quy ước mới". Điều này cũng giống như khám phá bất kỳ loại quy ước lập trình nào khác. Bạn chỉ cần đi với nó. Bạn có thể đi chệch hướng, nhưng bạn chỉ cô lập chính mình. .
Joe

100

Đó không chỉ là phong cách xấu, nó có thể dẫn đến hành vi bất ngờ khi sử dụng các công cụ khác trên tệp.

Đây là test.txt:

first line
second line

Không có ký tự dòng mới trên dòng cuối cùng. Hãy xem có bao nhiêu dòng trong tệp:

$ wc -l test.txt
1 test.txt

Có thể đó là những gì bạn muốn, nhưng trong hầu hết các trường hợp, bạn có thể mong đợi có 2 dòng trong tệp.

Ngoài ra, nếu bạn muốn kết hợp các tệp, nó có thể không hoạt động theo cách bạn mong đợi:

$ cat test.txt test.txt
first line
second linefirst line
second line

Cuối cùng, nó sẽ làm cho sự khác biệt của bạn trở nên ồn ào hơn nếu bạn thêm một dòng mới. Nếu bạn đã thêm một dòng thứ ba, nó sẽ hiển thị một chỉnh sửa cho dòng thứ hai cũng như bổ sung mới.


4
Kết quả của mèo là ok nhưng tham số wc "-l, --lines" là sai. Ngay cả hướng dẫn sử dụng cũng nói "in số lượng dòng mới" và không "in số lượng dòng".
đáng kinh ngạc

Và tôi thậm chí không thể sao chép cái này (wc và cat) với linux linux (produc-linux 2.34) gần đây.
wget

1
@wget Tôi đang sử dụng linux -34 2.34 và nó có thể xác nhận rằng những gì câu trả lời này mô tả là hành vi hiện tại. Tôi đoán là trình soạn thảo của bạn đã thêm ký tự "\ n".
stephanos

29

Lý do duy nhất là Unix trong lịch sử đã có một quy ước về tất cả các tệp văn bản có thể đọc được của con người kết thúc bằng một dòng mới. Tại thời điểm đó, điều này tránh xử lý thêm khi hiển thị hoặc nối các tệp văn bản và tránh xử lý các tệp văn bản khác với các tệp chứa các loại dữ liệu khác (ví dụ: dữ liệu nhị phân thô không thể đọc được).

Do quy ước này, nhiều công cụ từ thời kỳ đó mong đợi dòng mới kết thúc, bao gồm trình soạn thảo văn bản, công cụ tìm khác biệt và các công cụ xử lý văn bản khác. Mac OS X được xây dựng trên BSD Unix và Linux được phát triển để tương thích với Unix, vì vậy cả hai hệ điều hành đều được thừa hưởng cùng một quy ước, hành vi và công cụ.

Windows không được phát triển để tương thích với Unix, do đó, nó không có cùng một quy ước và hầu hết các phần mềm Windows sẽ hoạt động tốt mà không có dòng mới.

Nhưng, vì Git được phát triển cho Linux trước tiên và rất nhiều phần mềm nguồn mở được xây dựng trên các hệ thống tương thích Unix như Linux, Mac OS X, FreeBSD, v.v., hầu hết các cộng đồng nguồn mở và các công cụ của họ (bao gồm cả ngôn ngữ lập trình) vẫn tiếp tục để theo các quy ước này.

Có những lý do kỹ thuật có ý nghĩa vào năm 1971, nhưng trong thời đại này, nó chủ yếu là quy ước và duy trì khả năng tương thích với các công cụ hiện có.


23

Nếu bạn thêm một dòng văn bản mới vào cuối tệp hiện tại chưa có newline characterở cuối, thì diff sẽ hiển thị dòng cuối cùng cũ như đã được sửa đổi, mặc dù về mặt khái niệm thì không.

Đây là ít nhất một lý do tốt để thêm newline charactervào cuối.

Thí dụ

Một tệp chứa:

A() {
    // do something
}

Hexdump:

00000000: 4128 2920 7b0a 2020 2020 2f2f 2064 6f20  A() {.    // do 
00000010: 736f 6d65 7468 696e 670a 7d              something.}

Bây giờ bạn chỉnh sửa nó thành

A() {
    // do something
}
// Useful comment

Hexdump:

00000000: 4128 2920 7b0a 2020 2020 2f2f 2064 6f20  A() {.    // do 
00000010: 736f 6d65 7468 696e 670a 7d0a 2f2f 2055  something.}.// U
00000020: 7365 6675 6c20 636f 6d6d 656e 742e 0a    seful comment..

Các git diff sẽ hiển thị:

-}
\ No newline at end of file
+}
+// Useful comment.

Nói cách khác, nó cho thấy một sự khác biệt lớn hơn so với khái niệm xảy ra. Nó cho thấy rằng bạn đã xóa dòng }và thêm dòng }\n. Trên thực tế, đây là những gì đã xảy ra, nhưng nó không phải là những gì đã xảy ra về mặt khái niệm , vì vậy nó có thể gây nhầm lẫn.


2
Chúng ta có thể viết điều tương tự theo hướng khác: Nếu bạn xóa một dòng mới ở cuối tệp hiện có ở cuối dòng, thì diff sẽ hiển thị dòng cuối cùng cũ như đã sửa đổi, khi về mặt khái niệm thì không. Ít nhất một lý do tốt để loại bỏ một dòng mới vào cuối.
gentiane

3
@gentiane Bạn đang nhầm lẫn "một dòng mới" (một dòng mới) và "một dòng mới" (1 hoặc 2 ký tự phân định cuối dòng)
minexew

@minexew Không, gentiane thì không. Có thể bạn không nhận ra rằng "một dòng mới" giống như "một dòng mới".
Không thể tin được vào

3
@TheincredibleJan Cách họ được sử dụng trong câu trả lời, hai thuật ngữ có ý nghĩa riêng biệt. Tôi không biết nếu bạn đang cố gắng trở thành một người thông minh hay chỉ là hiểu lầm những gì đang diễn ra.
minexew

18

Nó chỉ ra rằng phần cuối của tệp không có dòng mới. Đó không phải là một thảm họa, nó chỉ là một thông điệp để làm rõ hơn rằng không có ai khi nhìn vào một khác biệt trong dòng lệnh.


10

Lý do quy ước này được áp dụng là vì trên các hệ điều hành giống UNIX, một ký tự dòng mới được coi là dấu kết thúc dòng và / hoặc ranh giới thông báo (bao gồm đường ống giữa các quy trình, bộ đệm dòng, v.v.).

Ví dụ, xem xét rằng một tệp chỉ có một ký tự dòng mới được coi là một dòng trống duy nhất. Ngược lại, một tệp có độ dài bằng 0 byte thực sự là một tệp trống có các dòng bằng không. Điều này có thể được xác nhận theo wc -llệnh.

Nhìn chung, hành vi này là hợp lý bởi vì sẽ không có cách nào khác để phân biệt giữa một tệp văn bản trống so với tệp văn bản với một dòng trống duy nhất nếu \nký tự chỉ là dấu phân cách dòng chứ không phải là dấu kết thúc dòng. Do đó, các tệp văn bản hợp lệ phải luôn luôn kết thúc bằng một ký tự dòng mới. Ngoại lệ duy nhất là nếu tệp văn bản được dự định để trống (không có dòng).


1
Tại sao tôi bị đánh giá thấp -2? Tôi đã chỉ ra không chỉ xác nhận những gì các câu trả lời khác đã nêu (tức là các công cụ dựa trên UNIX tiêu chuẩn mong muốn một dòng mới là một đầu cuối cho các dòng) mà còn không có cách nào để phân biệt một tệp trống với một dòng trống duy nhất, điều này hoàn toàn đúng . Tôi đặc biệt trả lời câu hỏi ban đầu "Ý nghĩa của thông điệp là gì và nó đang cố nói gì với chúng tôi?"
Leslie Krause

Tôi không đánh giá thấp bạn nhưng phản hồi này dường như đặc trưng cho các hệ thống loại Unix ở chỗ nó chỉ áp dụng khi một dòng mới chỉ là ký tự dòng mới. Không rõ ràng rằng áp dụng ở đây. Ngoài ra, cảnh báo dường như vô dụng nếu tệp chỉ bao gồm một dòng trống. Tuy nhiên tôi tránh Stackoverflow vì mọi người thường downvote mà không có lời giải thích.
user34660

9

Có một điều mà tôi không thấy trong các phản hồi trước đây. Cảnh báo về việc không có dòng cuối có thể là một cảnh báo khi một phần của tệp đã bị cắt ngắn. Nó có thể là một triệu chứng của dữ liệu bị thiếu.


Điểm tốt nói chung, nhưng tôi không nghĩ nó có ý nghĩa trong bối cảnh của câu hỏi đặc biệt này.
cst1992

@ cst1992 Câu trả lời trong Stackoverflow được cho là hữu ích nhất có thể, có nghĩa là chúng được cho là áp dụng cho tất cả các khả năng. Câu hỏi ngắn và tôi không thấy nó loại trừ khả năng tôi đề xuất.
user34660

7

Vấn đề cốt lõi là những gì bạn xác định dòng và liệu chuỗi ký tự cuối dòng có phải là một phần của dòng hay không. Các trình soạn thảo dựa trên UNIX (như VIM) hoặc các công cụ (như Git) sử dụng chuỗi ký tự EOL làm đầu cuối dòng, do đó nó là một phần của dòng. Nó tương tự như việc sử dụng dấu chấm phẩy (;) trong C và Pascal. Trong dấu chấm phẩy C chấm dứt các câu lệnh, trong Pascal, nó phân tách chúng.


4

Điều này thực sự gây ra vấn đề vì các kết thúc dòng được tự động sửa đổi các tệp bẩn mà không thực hiện bất kỳ thay đổi nào đối với chúng. Xem bài này để giải quyết.

git thay thế LF bằng CRLF


3

Các tệp nguồn thường được nối bởi các công cụ (C, C ++: tệp tiêu đề, Javascript: gói). Nếu bạn bỏ qua ký tự dòng mới, bạn có thể đưa ra các lỗi khó chịu (trong đó dòng cuối cùng của một nguồn được nối với dòng đầu tiên của tệp nguồn tiếp theo). Hy vọng rằng tất cả các công cụ nối mã nguồn ngoài đó đều chèn một dòng mới giữa các tệp được nối nhưng dù sao thì điều đó dường như không phải là trường hợp.

Mấu chốt của vấn đề là - trong hầu hết các ngôn ngữ, dòng mới có ý nghĩa ngữ nghĩa và phần cuối của tệp không phải là ngôn ngữ được xác định thay thế cho ký tự dòng mới. Vì vậy, bạn nên chấm dứt mọi tuyên bố / biểu thức bằng một ký tự dòng mới - bao gồm cả ký tự cuối cùng.


1
Trong C / C ++, bạn có thể viết toàn bộ dự án của mình thành một dòng. Không cần dòng mới.
đáng kinh ngạc

Bạn có thể viết toàn bộ dự án của mình thành một dòng ... nếu bạn không sử dụng //nhận xét kiểu ở giữa mã.
Doug Coburn

2

Tập tin gốc của bạn có thể không có ký tự dòng mới.

Tuy nhiên, một số trình soạn thảo như gedit trong linux âm thầm thêm dòng mới vào cuối tệp. Bạn không thể thoát khỏi tin nhắn này trong khi sử dụng loại trình soạn thảo này.

Điều tôi đã cố gắng khắc phục vấn đề này là mở tệp bằng trình chỉnh sửa mã phòng thu trực quan

Trình chỉnh sửa này hiển thị rõ ràng dòng cuối cùng và bạn có thể xóa dòng theo ý muốn.


0

Để biết giá trị của nó, tôi đã gặp phải điều này khi tôi tạo một dự án IntelliJ trên máy Mac, và sau đó chuyển dự án sang máy Windows của tôi. Tôi đã phải tự mở mọi tệp và thay đổi cài đặt mã hóa ở dưới cùng bên phải của cửa sổ IntelliJ. Có lẽ không xảy ra với hầu hết mọi người nếu đọc câu hỏi này nhưng điều đó có thể giúp tôi tiết kiệm được một vài giờ làm việc ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.