Saya berasumsi semua orang di sini terbiasa dengan pepatah bahwa semua file teks harus diakhiri dengan baris baru. Saya sudah tahu tentang "aturan" ini selama bertahun-tahun tetapi saya selalu bertanya-tanya - mengapa?
file
unix
text-files
newline
Will Robertson
sumber
sumber
Jawaban:
Karena begitulah standar POSIX mendefinisikan garis :
Oleh karena itu, garis yang tidak diakhiri dengan karakter baris baru tidak dianggap sebagai garis yang sebenarnya. Itu sebabnya beberapa program mengalami masalah dalam memproses baris terakhir file jika tidak diakhiri baris baru.
Ada setidaknya satu keuntungan sulit untuk pedoman ini ketika bekerja pada emulator terminal: Semua alat Unix mengharapkan konvensi ini dan bekerja dengannya. Misalnya, ketika menggabungkan file dengan
cat
, file yang diakhiri oleh baris baru akan memiliki efek yang berbeda dari yang tanpa:Dan, seperti contoh sebelumnya juga menunjukkan, ketika menampilkan file pada baris perintah (misalnya via
more
), file yang diakhiri baris baru menghasilkan tampilan yang benar. File yang dihentikan secara tidak benar mungkin rusak (baris kedua).Untuk konsistensi, sangat membantu untuk mengikuti aturan ini - melakukan hal lain akan membuat pekerjaan tambahan ketika berhadapan dengan alat Unix default.
Pikirkan secara berbeda: Jika baris tidak diakhiri oleh baris baru, membuat perintah seperti
cat
berguna jauh lebih sulit: bagaimana Anda membuat perintah untuk menggabungkan file sedemikian rupa sehinggab.txt
danc.txt
?Tentu saja ini dapat dipecahkan tetapi Anda perlu membuat penggunaan yang
cat
lebih kompleks (dengan menambahkan argumen baris perintah posisional, misalnyacat a.txt --no-newline b.txt c.txt
), dan sekarang perintah daripada masing-masing file individu mengontrol bagaimana ia ditempelkan bersama dengan file lain. Ini hampir pasti tidak nyaman.... Atau Anda perlu memperkenalkan karakter penjaga khusus untuk menandai garis yang seharusnya dilanjutkan daripada dihentikan. Nah, sekarang Anda terjebak dengan situasi yang sama seperti pada POSIX, kecuali terbalik (kelanjutan garis daripada karakter pemutusan garis).
Sekarang, pada sistem yang tidak sesuai dengan POSIX (saat ini sebagian besar adalah Windows), intinya adalah dapat diperdebatkan: file umumnya tidak berakhir dengan baris baru, dan definisi (informal) dari sebuah baris misalnya “teks yang dipisahkan oleh baris baru” (perhatikan penekanannya). Ini sepenuhnya valid. Namun, untuk data terstruktur (misalnya kode pemrograman) itu membuat parsing minimal lebih rumit: umumnya berarti parser harus ditulis ulang. Jika parser pada awalnya ditulis dengan definisi POSIX dalam pikiran, maka mungkin lebih mudah untuk memodifikasi aliran token daripada parser - dengan kata lain, tambahkan token "baris baru buatan" ke akhir input.
sumber
cat
cara yang bermanfaat dan konsisten.Setiap baris harus diakhiri dalam karakter baris baru, termasuk yang terakhir. Beberapa program memiliki masalah dalam memproses baris terakhir file jika tidak dihentikan baris baru.
GCC memperingatkannya bukan karena tidak dapat memproses file, tetapi karena itu harus sebagai bagian dari standar.
Referensi: Arsip surat GCC / GNU .
sumber
wc -l
tidak akan menghitung baris terakhir file jika bukan baris baru dihentikan. Juga,cat
akan bergabung dengan baris terakhir file dengan baris pertama file berikutnya menjadi satu jika baris terakhir dari file pertama tidak diakhiri baris baru. Hampir semua program yang mencari baris baru sebagai pembatas berpotensi mengacaukannya.wc
telah telah disebutkan ....cat
danwc
)?Jawaban ini merupakan upaya jawaban teknis daripada pendapat.
Jika kita ingin menjadi purix POSIX, kita mendefinisikan sebuah baris sebagai:
Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Baris tidak lengkap sebagai:
Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
File teks sebagai:
Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Sebuah string sebagai:
Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
Dari sini, kita dapat memperoleh bahwa satu-satunya waktu kita berpotensi akan menghadapi semua jenis masalah adalah jika kita berurusan dengan konsep garis file atau file sebagai file teks (adalah bahwa file teks adalah organisasi nol atau lebih banyak baris, dan baris yang kita tahu harus diakhiri dengan <newline>).
Contoh kasus:
wc -l filename
.Dari
wc
manual yang kita baca:Apa implikasinya terhadap file JavaScript, HTML, dan CSS kemudian menjadi file teks ?
Di browser, IDE modern, dan aplikasi front-end lainnya tidak ada masalah dengan melewatkan EOL di EOF. Aplikasi akan mem-parsing file dengan benar. Itu harus karena tidak semua Sistem Operasi sesuai dengan standar POSIX, sehingga akan menjadi tidak praktis untuk alat-alat non-OS (misalnya browser) untuk menangani file sesuai dengan standar POSIX (atau standar level OS apa pun).
Sebagai hasilnya, kita dapat relatif yakin bahwa EOL di EOF hampir tidak akan memiliki dampak negatif pada tingkat aplikasi - terlepas dari apakah itu berjalan pada OS UNIX.
Pada titik ini kita dapat dengan yakin mengatakan bahwa melewatkan EOL di EOF adalah aman ketika berhadapan dengan JS, HTML, CSS di sisi klien. Sebenarnya, kita dapat menyatakan bahwa meminimalkan salah satu dari file-file ini, tidak mengandung <newline> aman.
Kita dapat mengambil satu langkah lebih jauh dan mengatakan bahwa sejauh menyangkut NodeJS, ia juga tidak dapat mematuhi standar POSIX yang dapat dijalankan di lingkungan yang tidak memenuhi POSIX.
Apa yang tersisa dengan kita? Perkakas tingkat sistem.
Ini berarti satu-satunya masalah yang mungkin timbul adalah dengan alat yang berupaya untuk mematuhi fungsionalitasnya ke semantik POSIX (misalnya definisi garis seperti yang ditunjukkan pada
wc
).Meski begitu, tidak semua cangkang akan secara otomatis mematuhi POSIX. Bash misalnya tidak default untuk perilaku POSIX. Ada saklar untuk mengaktifkannya:
POSIXLY_CORRECT
.Makanan yang dipikirkan tentang nilai EOL adalah <newline>: https://www.rfc-editor.org/old/EOLstory.txt
Tetap berada di jalur perkakas, untuk semua maksud dan tujuan praktis, mari kita pertimbangkan ini:
Mari kita bekerja dengan file yang tidak memiliki EOL. Pada penulisan ini file dalam contoh ini adalah JavaScript yang diperkecil tanpa EOL.
Perhatikan
cat
ukuran file persis jumlah dari masing-masing bagian. Jika penggabungan file JavaScript adalah masalah untuk file JS, perhatian yang lebih tepat adalah memulai setiap file JavaScript dengan titik koma.Seperti orang lain yang disebutkan di utas ini: bagaimana jika Anda ingin
cat
dua file yang outputnya menjadi hanya satu baris, bukan dua? Dengan kata lain,cat
lakukan apa yang seharusnya dilakukan.Satu
man
-cat
satunya menyebutkan input pembacaan hingga EOF, bukan <newline>. Perhatikan bahwa-n
saklarcat
juga akan mencetak garis yang diakhiri non-<newline> (atau garis tidak lengkap ) sebagai garis - artinya penghitungan dimulai dari 1 (sesuai denganman
.)Sekarang kita mengerti bagaimana POSIX mendefinisikan sebuah garis , perilaku ini menjadi ambigu, atau benar-benar, tidak sesuai.
Memahami tujuan dan kepatuhan alat tertentu akan membantu dalam menentukan seberapa penting untuk mengakhiri file dengan EOL. Dalam C, C ++, Java (JARs), dll ... beberapa standar akan menentukan baris baru untuk validitas - tidak ada standar seperti itu untuk JS, HTML, CSS.
Misalnya, alih-alih menggunakan
wc -l filename
satu dapat melakukannyaawk '{x++}END{ print x}' filename
, dan yakinlah bahwa keberhasilan tugas tidak terancam oleh file yang mungkin ingin kami proses yang tidak kami tulis (mis. Perpustakaan pihak ketiga seperti JS yang diperkecil, kamicurl
d) - kecuali kami maksudnya adalah benar-benar menghitung garis dalam arti yang sesuai dengan POSIX.Kesimpulan
Akan ada beberapa kasus penggunaan kehidupan nyata di mana melewatkan EOL di EOF untuk file teks tertentu seperti JS, HTML, dan CSS akan memiliki dampak negatif - jika sama sekali. Jika kami mengandalkan <newline> yang ada, kami membatasi keandalan perkakas kami hanya untuk file yang kami buat dan membuka diri terhadap kemungkinan kesalahan yang diperkenalkan oleh file pihak ketiga.
Moral dari cerita: Perkakas insinyur yang tidak memiliki kelemahan mengandalkan EOL di EOF.
Jangan ragu untuk memposting kasus penggunaan karena berlaku untuk JS, HTML dan CSS di mana kita dapat memeriksa bagaimana melewatkan EOL memiliki efek buruk.
sumber
Ini mungkin terkait dengan perbedaan antara :
Jika setiap baris berakhir dengan end-of-line, ini menghindari, misalnya, menggabungkan dua file teks akan membuat baris terakhir dijalankan pertama kali ke baris pertama baris kedua.
Plus, seorang editor dapat memeriksa pada saat memuat apakah file berakhir di end-of-line, menyimpannya di opsi lokal 'eol', dan menggunakannya saat menulis file.
Beberapa tahun yang lalu (2005), banyak editor (ZDE, Eclipse, Scite, ...) memang "melupakan" EOL akhir itu, yang sangat tidak dihargai .
Bukan hanya itu, tetapi mereka menafsirkan EOL akhir itu secara tidak benar, sebagai 'mulai baris baru', dan benar-benar mulai menampilkan baris lain seolah-olah sudah ada.
Ini sangat terlihat dengan file teks 'tepat' dengan editor teks yang berperilaku baik seperti vim, dibandingkan dengan membukanya di salah satu editor di atas. Ini menampilkan baris tambahan di bawah baris terakhir file. Anda melihat sesuatu seperti ini:
sumber
Beberapa alat mengharapkan ini. Misalnya,
wc
mengharapkan ini:sumber
wc
tidak mengharapkan ini, sebanyak itu hanya bekerja dalam definisi POSIX dari "garis" yang bertentangan dengan pemahaman intuitif kebanyakan orang tentang "garis".wc -l
mencetak1
dalam kedua kasus, tetapi beberapa orang mungkin mengatakan kasus kedua harus dicetak2
.\n
sebagai terminator garis, bukan sebagai pemisah garis, seperti POSIX / UNIX, maka mengharapkan case kedua untuk mencetak 2 benar-benar gila.Pada dasarnya ada banyak program yang tidak akan memproses file dengan benar jika mereka tidak mendapatkan EOL EOF akhir.
GCC memperingatkan Anda tentang ini karena itu diharapkan sebagai bagian dari standar C. (bagian 5.1.1.2 rupanya)
Peringatan kompiler "Tidak ada baris baru di akhir file"
sumber
Ini berasal dari hari-hari awal ketika terminal sederhana digunakan. Char baris baru digunakan untuk memicu 'flush' dari data yang ditransfer.
Hari ini, baris baru char tidak diperlukan lagi. Tentu, banyak aplikasi yang masih memiliki masalah jika baris baru tidak ada, tetapi saya menganggapnya sebagai bug pada aplikasi tersebut.
Namun jika Anda memiliki format file teks di mana Anda memerlukan baris baru, Anda mendapatkan verifikasi data sederhana sangat murah: jika file berakhir dengan baris yang tidak memiliki baris baru di akhir, Anda tahu file rusak. Dengan hanya satu byte tambahan untuk setiap baris, Anda dapat mendeteksi file yang rusak dengan akurasi tinggi dan hampir tidak ada waktu CPU.
sumber
Kasus penggunaan terpisah: ketika file teks Anda dikontrol versi (dalam kasus ini khusus di bawah git meskipun itu berlaku untuk orang lain juga). Jika konten ditambahkan ke akhir file, maka baris yang sebelumnya baris terakhir akan diedit untuk memasukkan karakter baris baru. Ini berarti bahwa
blame
ing file untuk mengetahui kapan baris itu terakhir diedit akan menampilkan tambahan teks, bukan komit sebelum yang Anda benar-benar ingin lihat.sumber
\n
). Masalah terpecahkan.Selain alasan praktis di atas, tidak akan mengejutkan saya jika penggagas Unix (Thompson, Ritchie, et al.) Atau pendahulu Multics mereka menyadari bahwa ada alasan teoritis untuk menggunakan terminator garis daripada pemisah garis: Dengan garis terminator, Anda dapat menyandikan semua file baris yang mungkin. Dengan pemisah garis, tidak ada perbedaan antara file garis nol dan file yang berisi satu baris kosong; keduanya dikodekan sebagai file yang berisi karakter nol.
Jadi, alasannya adalah:
wc -l
tidak akan menghitung "garis" akhir jika tidak diakhiri dengan baris baru.cat
hanya berfungsi dan bekerja tanpa komplikasi. Itu hanya menyalin byte dari setiap file, tanpa perlu interpretasi. Saya tidak berpikir ada setara dengan DOScat
. Menggunakancopy a+b c
akan berakhir dengan menggabungkan baris terakhir filea
dengan baris pertama fileb
.sumber
Saya sudah bertanya-tanya sendiri selama bertahun-tahun. Tapi saya menemukan alasan bagus hari ini.
Bayangkan sebuah file dengan catatan di setiap baris (mis: file CSV). Dan komputer itu sedang menulis catatan di akhir file. Tapi tiba-tiba jatuh. Wah apakah baris terakhir selesai? (bukan situasi yang baik)
Tetapi jika kita selalu mengakhiri baris terakhir, maka kita akan tahu (cukup periksa apakah baris terakhir dihentikan). Kalau tidak, kita mungkin harus membuang baris terakhir setiap kali, hanya untuk aman.
sumber
Mungkin hanya beberapa kode parsing yang diharapkan ada di sana.
Saya tidak yakin saya akan menganggapnya sebagai "aturan", dan tentu saja itu bukan sesuatu yang saya patuhi secara religius. Kode yang paling masuk akal akan tahu cara mem-parsing teks (termasuk penyandian) baris demi baris (semua pilihan akhir baris), dengan-atau-tanpa baris baru pada baris terakhir.
Memang - jika Anda mengakhiri dengan baris baru: apakah ada (secara teori) garis akhir kosong antara EOL dan EOF? Satu untuk direnungkan ...
sumber
Ada juga masalah pemrograman praktis dengan file yang tidak memiliki baris baru di akhir:
read
Bash built-in (saya tidak tahu tentangread
implementasi lain ) tidak berfungsi seperti yang diharapkan:Ini hanya
foo
mencetak ! Alasannya adalah ketikaread
menemukan baris terakhir, ia menulis konten$line
tetapi mengembalikan kode 1 karena mencapai EOF. Ini memutuswhile
perulangan, jadi kami tidak pernah mencapaiecho $line
bagian itu. Jika Anda ingin menangani situasi ini, Anda harus melakukan hal berikut:Yaitu, lakukan
echo
jikaread
gagal karena baris tidak kosong di akhir file. Secara alami, dalam hal ini akan ada satu baris tambahan baru dalam output yang tidak ada dalam input.sumber
Seperti yang diungkapkan oleh banyak orang, karena:
Banyak program tidak berperilaku baik, atau gagal tanpanya.
Bahkan program yang menangani file dengan baik tidak memiliki akhiran
'\n'
, fungsionalitas alat mungkin tidak memenuhi harapan pengguna - yang mungkin tidak jelas dalam kasus sudut ini.Program jarang melarang final
'\n'
(saya tidak tahu ada).Namun ini menimbulkan pertanyaan berikutnya:
Paling penting - Jangan menulis kode yang menganggap file teks diakhiri dengan baris baru . Dengan asumsi file sesuai dengan format mengarah ke korupsi data, serangan hacker, dan crash. Contoh:
Jika trailing akhir
'\n'
diperlukan, beri tahu pengguna jika tidak ada dan tindakan telah diambil. TKI, validasi format file. Catatan: Ini mungkin termasuk batas panjang garis maksimum, pengkodean karakter, dll.Tentukan dengan jelas, dokumentasikan, penanganan kode dari final yang hilang
'\n'
.Jangan, sesering mungkin, menghasilkan file yang tidak memiliki akhir
'\n'
.sumber
Sangat terlambat di sini, tetapi saya hanya menghadapi satu bug dalam pemrosesan file dan itu datang karena file tidak berakhir dengan baris baru yang kosong. Kami sedang memproses file teks dengan
sed
dansed
menghilangkan baris terakhir dari output yang menyebabkan struktur json tidak valid dan mengirimkan sisa proses ke keadaan gagal.Yang kami lakukan adalah:
Ada satu file contoh mengatakan:
foo.txt
dengan beberapajson
konten di dalamnya.File itu dibuat di mesin janda dan skrip jendela sedang memproses file itu menggunakan perintah PowerShell. Semuanya bagus.
Ketika kami memproses file yang sama menggunakan
sed
perintahsed 's|value|newValue|g' foo.txt > foo.txt.tmp
File yang baru dibuat adalah
dan boom, itu gagal seluruh proses karena JSON tidak valid.
Jadi selalu merupakan praktik yang baik untuk mengakhiri file Anda dengan baris baru yang kosong.
sumber
Saya selalu mendapat kesan bahwa aturan datang dari hari-hari ketika mem-parsing file tanpa mengakhiri baris baru itu sulit. Artinya, Anda akan berakhir menulis kode di mana ujung garis didefinisikan oleh karakter EOL atau EOF. Itu lebih sederhana untuk mengasumsikan garis yang diakhiri dengan EOL.
Namun saya percaya aturan ini diturunkan dari kompiler C yang membutuhkan baris baru. Dan seperti yang ditunjukkan pada peringatan kompiler "Tidak ada baris baru di akhir file" , #include tidak akan menambahkan baris baru.
sumber
Bayangkan file sedang diproses sementara file masih dibuat oleh proses lain.
Mungkin itu ada hubungannya dengan itu? Bendera yang menunjukkan bahwa file siap diproses.
sumber
Saya pribadi suka baris baru di akhir file kode sumber.
Ini mungkin berasal dari Linux atau semua sistem UNIX dalam hal ini. Saya ingat ada kesalahan kompilasi (gcc jika saya tidak salah) karena file kode sumber tidak diakhiri dengan baris baru yang kosong. Mengapa itu dibuat dengan cara ini membuat orang bertanya-tanya.
sumber
IMHO, ini masalah gaya dan pendapat pribadi.
Di masa lalu, saya tidak memasukkan baris baru itu. Karakter yang disimpan berarti lebih cepat melalui modem 14.4K itu.
Kemudian, saya meletakkan baris baru itu sehingga lebih mudah untuk memilih baris terakhir menggunakan shift + downarrow.
sumber