it-swarm-vi.com

Điểm nào trong việc thêm một dòng mới vào cuối tập tin?

Một số trình biên dịch (đặc biệt là các trình biên dịch C hoặc C++) cung cấp cho bạn các cảnh báo về:

No new line at end of file

Tôi nghĩ rằng đây sẽ là một vấn đề chỉ dành cho lập trình viên C, nhưng github hiển thị một thông báo trong chế độ xem cam kết:

\ No newline at end of file

cho tệp PHP.

Tôi hiểu điều tiền xử lý được giải thích trong chủ đề này , nhưng điều này có liên quan gì đến PHP? Đây có phải là cùng một thứ include() hay nó có liên quan đến chủ đề \r\n So với \n?

Điểm có một dòng mới ở cuối tập tin là gì?

197
Philipp Stephan

Đây không phải là về việc thêm một dòng mới vào cuối tập tin, mà là về việc không xóa dòng mới sẽ có ở đó.

A tệp văn bản , dưới unix, bao gồm một chuỗi dòng , mỗi tệp kết thúc bằng một ký tự dòng mới (\n). Do đó, một tệp không trống và không kết thúc bằng một dòng mới không phải là một tệp văn bản.

Các tiện ích được cho là hoạt động trên các tệp văn bản có thể không phù hợp với các tệp không kết thúc bằng một dòng mới; các tiện ích Unix lịch sử có thể bỏ qua văn bản sau dòng mới nhất, ví dụ. GNU tiện ích có chính sách ứng xử chặt chẽ với các tệp không phải văn bản và hầu hết các tiện ích hiện đại khác cũng vậy, nhưng bạn vẫn có thể gặp phải hành vi kỳ lạ với các tệp thiếu một dòng mới cuối cùng¹.

Với GNU diff, nếu một trong các tệp được so sánh kết thúc bằng một dòng mới nhưng không phải là tệp khác, thì nên lưu ý thực tế đó. Vì diff là định hướng theo dòng, nên nó không thể chỉ ra điều này bằng cách lưu trữ một dòng mới cho một trong các tệp nhưng không phải cho các tệp khác - các dòng mới là cần thiết để chỉ ra nơi mỗi dòng trong tệp diff bắt đầu và kết thúc. Vì vậy, diff sử dụng văn bản đặc biệt này \ No newline at end of file để phân biệt một tệp không kết thúc trong một dòng mới với một tệp đã làm.

Nhân tiện, trong ngữ cảnh C, một tệp nguồn tương tự bao gồm một loạt các dòng. Chính xác hơn, một đơn vị dịch thuật được xem trong một triển khai - được định nghĩa là một chuỗi các dòng, mỗi dòng phải kết thúc bằng một ký tự dòng mới ( n1256 §5.1.1.1). Trên các hệ thống unix, ánh xạ rất đơn giản. Trên DOS và Windows, mỗi chuỗi CR LF (\r\n) được ánh xạ tới một dòng mới (\n; đây là điều luôn xảy ra khi đọc tệp được mở dưới dạng văn bản trên các hệ điều hành này). Có một số HĐH không có ký tự dòng mới, nhưng thay vào đó có các bản ghi có kích thước cố định hoặc có thể thay đổi; trên các hệ thống này, ánh xạ từ tệp đến nguồn C giới thiệu một \n ở cuối mỗi bản ghi. Mặc dù điều này không liên quan trực tiếp đến unix, nhưng điều đó có nghĩa là nếu bạn sao chép tệp nguồn C thiếu dòng mới cuối cùng của nó sang hệ thống có tệp văn bản dựa trên bản ghi, sau đó sao chép lại, bạn sẽ kết thúc với phần chưa hoàn chỉnh dòng cuối cùng bị cắt bớt trong chuyển đổi ban đầu hoặc một dòng mới bổ sung được xử lý trong quá trình chuyển đổi ngược lại.

¹ Ví dụ: đầu ra của GNU sort luôn kết thúc bằng một dòng mới. Vì vậy, nếu tệp foo bị thiếu dòng mới cuối cùng, bạn sẽ thấy rằng sort foo | wc -c báo cáo một ký tự nhiều hơn cat foo | wc -c.

223

Không nhất thiết là lý do, nhưng hậu quả thực tế của các tệp không kết thúc bằng một dòng mới:

Xem xét những gì sẽ xảy ra nếu bạn muốn xử lý một số tệp bằng cách sử dụng cat. Chẳng hạn, nếu bạn muốn tìm Word foo ở đầu dòng trên 3 tệp:

cat file1 file2 file3 | grep -e '^foo'

Nếu dòng đầu tiên trong tệp3 bắt đầu bằng foo, nhưng tệp2 không có \n Cuối cùng sau dòng cuối cùng của nó, thì sự xuất hiện này sẽ không được tìm thấy bởi grep, bởi vì dòng cuối cùng trong tệp2 và dòng đầu tiên trong file3 sẽ được grep xem là một dòng đơn.

Vì vậy, để thống nhất và để tránh những điều bất ngờ, tôi cố gắng giữ cho các tệp của mình luôn kết thúc bằng một dòng mới.

48
Sergio Acosta

Có hai khía cạnh:

  1. Có/đã có một số trình biên dịch C không thể phân tích cú pháp dòng cuối cùng nếu nó không kết thúc bằng một dòng mới. Tiêu chuẩn C chỉ định rằng tệp C sẽ kết thúc bằng một dòng mới (C11, 5.1.1.2, 2.) và một dòng cuối cùng không có dòng mới mang lại hành vi không xác định (mục C11, J.2, mục 2). Có lẽ vì lý do lịch sử, bởi vì một số nhà cung cấp trình biên dịch như vậy là một phần của ủy ban khi tiêu chuẩn đầu tiên được viết. Do đó, cảnh báo của GCC.

  2. diff chương trình (như được sử dụng bởi git diff, github, v.v.) hiển thị từng dòng khác nhau giữa các tệp. Họ thường in một tin nhắn khi chỉ một tập tin kết thúc bằng một dòng mới bởi vì bạn sẽ không thấy sự khác biệt này. Ví dụ: nếu sự khác biệt duy nhất giữa hai tệp là sự hiện diện của ký tự dòng mới cuối cùng, nếu không có gợi ý thì có vẻ như cả hai tệp đều giống nhau, khi diffcmp trả về một lối thoát- mã thành công không đồng đều và tổng kiểm tra của các tệp (ví dụ: thông qua md5sum) không khớp.

17
maxschlepzig

\ No newline at end of file Bạn nhận được từ github xuất hiện ở cuối bản vá (trong diff format , xem ghi chú ở cuối của phần "Định dạng hợp nhất").

Trình biên dịch không quan tâm liệu có dòng mới hay không ở cuối tệp, nhưng git (và các tiện ích diff/patch) phải đưa những tài khoản đó vào tài khoản . Có nhiều lý do cho điều đó. Ví dụ: việc quên thêm hoặc xóa một dòng mới ở cuối tệp sẽ thay đổi hàm băm của nó (md5sum/sha1sum). Ngoài ra, các tệp không phải lúc nào cũng là chương trình và \n Cuối cùng có thể tạo ra một số khác biệt.

Lưu ý : Về cảnh báo từ trình biên dịch C, tôi đoán họ khăng khăng cho một dòng mới cuối cùng cho mục đích tương thích ngược. Trình biên dịch rất cũ có thể không chấp nhận dòng cuối cùng nếu không kết thúc bằng \n (Hoặc chuỗi char cuối dòng phụ thuộc hệ thống khác).

12
Stéphane Gimenez

Ngoài ra còn có quan điểm giữ lịch sử khác biệt. Nếu một tệp kết thúc mà không có ký tự dòng mới, thì việc thêm bất cứ thứ gì vào cuối tệp sẽ được xem bởi các tiện ích khác như thay đổi dòng cuối cùng đó (vì \n đang được thêm vào nó).

Điều này có thể gây ra kết quả không mong muốn với các lệnh như git blamehg annotate.

6
Hosam Aly

POSIX, đây là một bộ tiêu chuẩn được chỉ định bởi IEEE để duy trì khả năng tương thích giữa các hệ điều hành.

Một trong số đó là định nghĩa của một "dòng" là một chuỗi có 0 hoặc nhiều ký tự không cộng với một ký tự dòng mới kết thúc.

Vì vậy, để dòng cuối cùng được công nhận là một "dòng" thực sự, nó phải có một ký tự dòng mới kết thúc.

Điều này rất quan trọng nếu bạn phụ thuộc vào các công cụ hệ điều hành để nói số lượng dòng hoặc phân tách/trợ giúp phân tích tệp của bạn. Được đưa ra PHP là ngôn ngữ kịch bản, hoàn toàn có thể, đặc biệt là trong những ngày đầu hoặc ngay cả bây giờ (tôi không có ý tưởng/định đề) nó có các phụ thuộc hệ điều hành như thế.

Trong thực tế, hầu hết các hệ điều hành không hoàn toàn tuân thủ POSIX và con người không thích máy đó hoặc thậm chí quan tâm đến việc chấm dứt các dòng mới. Vì vậy, đối với hầu hết mọi thứ, nó là một bữa tiệc tất cả mọi thứ quan tâm đến nó, cảnh báo hoặc chỉ đi phần cuối của văn bản thực sự là một dòng vì vậy chỉ cần bao gồm nó.

4
user3379747