Apa gunanya menambahkan baris baru ke akhir file?

166

Beberapa kompiler (terutama yang C atau C ++) memberi Anda peringatan tentang:

No new line at end of file

Saya pikir ini akan menjadi masalah C-programer saja, tetapi github menampilkan pesan dalam tampilan komit:

\ No newline at end of file

untuk file PHP.

Saya mengerti hal preprocessor yang dijelaskan di utas ini , tetapi apa hubungannya dengan PHP? Apakah hal yang sama include()atau terkait dengan topik \r\nvs \n?

Apa gunanya memiliki baris baru di akhir file?

Philipp Stephan
sumber
Gandakan dari SO: stackoverflow.com/questions/729692/…
AlikElzin-kilaka
2
Untuk membuat orang marah.
Andrew
4
Jika Anda catfile, prompt berikutnya akan ditambahkan ke "baris" akhir jika tidak diakhiri dengan baris baru.
Aaron Franke

Jawaban:

188

Ini bukan tentang menambahkan baris baru ekstra di akhir file, ini tentang tidak menghapus baris baru yang seharusnya ada di sana.

Sebuah file teks , di bawah unix, terdiri dari serangkaian garis , yang masing-masing berakhir dengan karakter baris baru ( \n). Karena itu file yang tidak kosong dan tidak diakhiri dengan baris baru bukanlah file teks.

Utilitas yang seharusnya beroperasi pada file teks mungkin tidak dapat mengatasi dengan baik file yang tidak berakhir dengan baris baru; Utilitas historis Unix mungkin mengabaikan teks setelah baris baru terakhir, misalnya. Utilitas GNU memiliki kebijakan berperilaku sopan dengan file non-teks, dan begitu juga sebagian besar utilitas modern lainnya, tetapi Anda mungkin masih menemukan perilaku aneh dengan file yang kehilangan baris baru akhir¹.

Dengan GNU diff, jika salah satu file yang dibandingkan diakhiri dengan baris baru tetapi tidak yang lain, perlu diperhatikan fakta itu. Karena diff berorientasi garis, ia tidak dapat menunjukkan ini dengan menyimpan baris baru untuk salah satu file tetapi tidak untuk yang lain - baris baru diperlukan untuk menunjukkan di mana setiap baris dalam file diff mulai dan berakhir. Jadi diff menggunakan teks khusus ini \ No newline at end of fileuntuk membedakan file yang tidak berakhir pada baris baru dari file yang melakukannya.

Omong-omong, dalam konteks C, file sumber juga terdiri dari serangkaian baris. Lebih tepatnya, unit terjemahan dilihat dalam implementasi-didefinisikan sebagai serangkaian garis, yang masing-masing harus diakhiri dengan karakter baris baru ( n1256 §5.1.1.1). Pada sistem unix, pemetaannya mudah. Pada DOS dan Windows, setiap urutan CR LF ( \r\n) dipetakan ke baris baru ( \n; inilah yang selalu terjadi ketika membaca file yang dibuka sebagai teks pada OS ini). Ada beberapa OS di luar sana yang tidak memiliki karakter baris baru, tetapi sebaliknya memiliki catatan berukuran tetap atau variabel; pada sistem ini, pemetaan dari file ke sumber C memperkenalkan a\ndi akhir setiap rekaman. Meskipun ini tidak secara langsung relevan dengan unix, itu berarti bahwa jika Anda menyalin file sumber C yang kehilangan baris terakhir terakhirnya ke sistem dengan file teks berbasis catatan, lalu menyalinnya kembali, Anda akan berakhir dengan yang tidak lengkap baris terakhir terpotong di konversi awal, atau baris baru tambahan ditempelkan selama konversi terbalik.

¹ Contoh: output dari jenis GNU selalu diakhiri dengan baris baru. Jadi, jika file footersebut kehilangan baris terakhirnya, Anda akan menemukan bahwa sort foo | wc -claporan memiliki satu karakter lebih banyak daripada cat foo | wc -c.

Gilles
sumber
Mengenai "... serangkaian garis, yang masing-masing harus diakhiri dengan karakter baris baru (n1256 §5.1.1.1)" -> Dalam melihat kembali C15R N1570 yang lebih baru, tidak menemukan dukungan untuk itu selain dari mungkin: "File sumber yang tidak kosong harus diakhiri dengan karakter baris baru, yang tidak akan segera diawali oleh karakter backslash sebelum terjadi splicing seperti itu." §5.1.1.2 2, tetapi itu tampaknya terbatas pada spesifikasi penyambungan.
chux
@Chux Kalimat itu juga ada di n1256. Baris terakhir harus diakhiri dengan karakter baris baru. Garis yang bukan baris terakhir harus jelas juga diakhiri dengan karakter baris baru untuk menunjukkan bahwa garis itu berakhir dan baris berikutnya dimulai. Dengan demikian setiap baris harus diakhiri dengan karakter baris baru.
Gilles
Hmmm, bagi saya, baris itu "" File sumber ... splicing terjadi. "Bisa dibatasi pada bagaimana pertimbangan splicing dan bukan file pada umumnya. Namun saya melihat bagaimana orang dapat melihat sebaliknya. Mungkin saya akan mencari posting yang berfokus pada hal itu
chux
> "Jadi, diff menggunakan teks khusus ini \ Tidak ada baris baru di akhir file untuk membedakan file yang tidak berakhir di baris baru dari file yang melakukannya." Git menunjukkan teks ini tidak hanya ketika membandingkan file. Tetapi bahkan ketika file baru ditambahkan ke git. Jadi argumen ini tidak valid, saya kira.
Viktor Kruglikov
> "Utilitas yang seharusnya beroperasi pada file teks mungkin tidak dapat mengatasi dengan baik file yang tidak diakhiri dengan baris baru" Saya tidak berpikir bahwa itu adalah urusan git untuk peduli dengan masalah tingkat rendah seperti hilang \ n karena POSIX Persyaratan. Saya pikir jika git menampilkan pesan ini, alasannya harus dalam masalah kontrol sumber .
Viktor Kruglikov
42

Tidak harus alasannya, tetapi konsekuensi praktis dari file tidak berakhir dengan baris baru:

Pertimbangkan apa yang akan terjadi jika Anda ingin memproses beberapa file menggunakan cat. Misalnya, jika Anda ingin menemukan kata foodi awal baris di 3 file:

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

Jika baris pertama dalam file3 dimulai dengan foo, tetapi file2 tidak memiliki akhir \nsetelah baris terakhir, kejadian ini tidak akan ditemukan oleh grep, karena baris terakhir di file2 dan baris pertama di file3 akan dilihat oleh grep sebagai satu baris.

Jadi, untuk konsistensi dan untuk menghindari kejutan saya mencoba untuk menjaga file saya selalu diakhiri dengan baris baru.

Sergio Acosta
sumber
Tapi apakah ini urusan git untuk peduli tentang penggabungan file?
Viktor Kruglikov
Bukankah masuk akal bahwa Anda harus memasukkan '\n'operasi kucing ...
Andrew
3
Itu seperti mengatakan, "Kadang-kadang saya menambahkan String bersama-sama yang memiliki \natau spasi kosong di ujungnya, jadi untuk menjaga hal-hal yang konsisten, saya selalu menempatkan \n _____di kedua ujung string saya." Ya, tidak, hal yang benar untuk dilakukan adalah membuat string Anda dipangkas dan kemudian menggabungkannya dengan benar.
Andrew
16

Ada dua aspek:

  1. Ada / ada beberapa kompiler C yang tidak dapat menguraikan baris terakhir jika tidak diakhiri dengan baris baru. Standar C menentukan bahwa file C harus diakhiri dengan baris baru (C11, 5.1.1.2, 2.) dan bahwa baris terakhir tanpa baris baru menghasilkan perilaku yang tidak terdefinisi (C11, J.2, item ke-2). Mungkin karena alasan historis, karena beberapa vendor kompiler seperti itu adalah bagian dari komite ketika standar pertama ditulis. Demikian peringatan dari GCC.

  2. diffprogram (seperti yang digunakan oleh git diff, github dll.) menunjukkan perbedaan baris demi baris antara file. Mereka biasanya mencetak pesan ketika hanya satu file yang diakhiri dengan baris baru karena jika tidak Anda tidak akan melihat perbedaan ini. Sebagai contoh jika satu-satunya perbedaan antara dua file adalah keberadaan karakter baris baru terakhir, tanpa petunjuk itu akan terlihat seperti kedua file itu sama, kapan diffdan cmpmengembalikan kode keluar keberhasilan yang tidak setara dan checksum dari file (misalnya via md5sum) tidak cocok.

maxschlepzig
sumber
masuk akal dengan program diff
Thamaraiselvam
Kedengarannya seperti diffs seharusnya lebih pintar.
Andrew
@Andrew, tidak, tidak. diffdiharapkan untuk mencetak perbedaan jika ada. Dan jika satu file memiliki baris baru sebagai karakter terakhir sementara yang lain belum maka perbedaan itu entah bagaimana harus terlihat dalam output.
maxschlepzig
Pernyataan terakhir Anda benar. Namun, penampil diff tidak harus menampilkan "baris baru" ( \n) untuk memulainya, ia hanya dapat menampilkan "baris baru".
Andrew
10

Yang \ No newline at end of fileAnda dapatkan dari github muncul di akhir tambalan (dalam diffformat , lihat catatan di akhir bagian "Format Terpadu").

Compiler tidak peduli apakah ada baris baru atau tidak di akhir file, tetapi git(dan diff/ patchutilitas) harus memperhitungkannya. Ada banyak alasan untuk itu. Sebagai contoh, lupa untuk menambah atau menghapus baris baru di akhir file akan mengubah hashsum-nya ( md5sum/ sha1sum). Juga, file tidak selalu program, dan final \nmungkin membuat beberapa perbedaan.

Catatan : Tentang peringatan dari kompiler C, saya kira mereka bersikeras untuk baris terakhir final untuk tujuan kompatibilitas ke belakang. Kompiler yang sangat lama mungkin tidak menerima baris terakhir jika tidak diakhiri dengan \n(atau urutan karakter end-of-line yang bergantung pada sistem).

Stéphane Gimenez
sumber
7
"Saya kira mereka bersikeras untuk baris baru terakhir untuk tujuan kompatibilitas mundur" - Tidak, mereka bersikeras karena standar C mengamanatkannya .
MestreLion
1
@MestreLion C membutuhkan baris baru akhir untuk kode sumber C (C11 §5.1.1.2 2). Perhatikan bahwa untuk file teks I / O, C memiliki "Apakah baris terakhir memerlukan penghentian karakter baris baru ditentukan oleh implementasi." §7.21.2 2
chux
Siapa yang menggunakan kompiler yang sangat lama? Berhenti menggunakannya.
Andrew
1
@MestreLion: Dan mengapa menurut Anda standar C mengamanatkannya ...
Stéphane Gimenez
@ StéphaneGimenez: konsistensi, kompatibilitas yang lebih baik, dan interoperabilitas di antara OS yang berbeda (POSIX juga mendefinisikan garis yang diakhiri dengan '\ n')
MestreLion
4

Ada juga titik menyimpan perbedaan sejarah. Jika file berakhir tanpa karakter baris baru, maka menambahkan apa pun ke akhir file akan dilihat oleh utilitas berbeda sebagai mengubah baris terakhir (karena \nsedang ditambahkan ke dalamnya).

Ini dapat menyebabkan hasil yang tidak diinginkan dengan perintah seperti git blamedan hg annotate.

Hosam Aly
sumber
Kedengarannya seperti diff hanya perlu lebih pintar.
Andrew
1
Alat yang berbeda sedang cerdas. Mereka memperhatikan perubahan halus pada file (yang penting karena pasti akan mengubah hash file). Dan baik GNU diff dan git diff menerima -wopsi untuk mengabaikan perubahan spasi putih saat mengeluarkan data untuk manusia.
joeytwiddle
4

POSIX, ini adalah seperangkat standar yang ditentukan oleh IEEE untuk menjaga kompatibilitas antara sistem operasi.

Salah satunya adalah definisi "garis" menjadi urutan nol atau lebih non-karakter plus karakter baris baru yang berakhir.

Jadi agar baris terakhir itu dikenali sebagai "garis" aktual, ia harus memiliki karakter baris baru yang diakhiri.

Ini penting jika Anda bergantung pada alat OS untuk mengatakan jumlah baris atau membagi / membantu mengurai file Anda. Mengingat PHP adalah bahasa skrip, sepenuhnya mungkin terutama pada hari-hari awal atau bahkan sekarang (saya tidak tahu / mendalilkan) itu dependensi OS seperti itu.

Pada kenyataannya, sebagian besar sistem operasi tidak sepenuhnya memenuhi persyaratan POSIX dan manusia tidak menyukai mesin itu atau bahkan peduli untuk menghentikan jalur baru. Jadi untuk sebagian besar hal itu merupakan hamparan segala sesuatu baik itu peduli, peringatan atau hanya pergi bahwa bit terakhir dari teks benar-benar sebuah baris jadi sertakan saja.

pengguna3379747
sumber