Mengapa file teks harus diakhiri dengan baris baru?

1470

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?

Will Robertson
sumber
30
hanya sebuah nitpick. itu bukan "baris baru" di akhir file. Ini adalah "jeda baris" pada akhir baris terakhir. Juga, lihat jawaban terbaik untuk pertanyaan terkait: stackoverflow.com/questions/16222530/…
gcb
346
Hanya untuk mencari lebih banyak lagi, ia tidak benar-benar menulis "baris baru", ia menulis "baris baru", yang benar.
sindrenm
5
tidak akrab, tetapi bertanya-tanya saya memang karena jumlah kasus di mana baris baru berlebihan sebenarnya melanggar hal-hal sedikit terlalu tinggi untuk selera saya
tobibeer
2
Saat ini saya menggunakan aliran Node.js untuk mem-parsing data baris-demi-baris, dan tidak adanya terminal-break mengganggu, karena saya harus menambahkan logika tambahan ketika sisi input dari aliran selesai / ditutup untuk memastikan bahwa baris terakhir diproses.
Mark K Cowan
23
The Cara Unix menganggap perilaku umum pada akhir file adalah sebagai berikut: \ n karakter tidak mulai baris; sebaliknya, mereka mengakhirinya. Jadi, \ n adalah terminator garis, bukan pemisah garis. Baris pertama (seperti semua baris) tidak perlu \ n untuk memulainya. Baris terakhir (seperti semua baris) membutuhkan \ n untuk mengakhirinya. An \ n di akhir file tidak membuat baris tambahan. Namun, kadang-kadang, editor teks akan menambahkan baris kosong yang terlihat di sana. Bahkan emacs melakukannya, secara opsional .
MarkDBlackwell

Jawaban:

1383

Karena begitulah standar POSIX mendefinisikan garis :

3.206 Baris
Urutan nol atau lebih karakter <newline> plus karakter terminasi <newline>.

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:

$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz

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 catberguna jauh lebih sulit: bagaimana Anda membuat perintah untuk menggabungkan file sedemikian rupa sehingga

  1. itu menempatkan setiap file mulai pada baris baru, yang adalah apa yang Anda inginkan 95% dari waktu; tapi
  2. memungkinkan penggabungan baris terakhir dan pertama dari dua file, seperti pada contoh di atas antara b.txtdan c.txt?

Tentu saja ini dapat dipecahkan tetapi Anda perlu membuat penggunaan yang catlebih kompleks (dengan menambahkan argumen baris perintah posisional, misalnya cat 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.

Konrad Rudolph
sumber
9
Meskipun sekarang cukup tidak praktis untuk diperbaiki, jelas POSIX melakukan kesalahan ketika mendefinisikan garis - sebagai bukti dari sejumlah pertanyaan mengenai masalah ini. Baris seharusnya didefinisikan sebagai nol atau lebih karakter yang diakhiri oleh <eol>, <eof>, atau <eol> <eof>. Kompleksitas Parser bukan masalah yang valid. Kompleksitas, sedapat mungkin, harus dipindahkan dari kepala programer ke perpustakaan.
Doug Coburn
23
@DougCoburn Jawaban ini digunakan untuk diskusi yang lengkap dan teknis menjelaskan mengapa ini salah, dan mengapa POSIX melakukan hal yang benar. Sayangnya komentar ini tampaknya baru-baru ini dihapus oleh moderator yang terlalu bersemangat. Secara singkat, ini bukan tentang penguraian kompleksitas; lebih tepatnya, definisi Anda mempersulit alat pembuat seperti catcara yang bermanfaat dan konsisten.
Konrad Rudolph
8
@Leon Aturan POSIX adalah tentang mengurangi kasus tepi. Dan itu sangat indah. Saya sebenarnya agak bingung bagaimana orang gagal memahami hal ini: Ini adalah definisi garis yang paling sederhana dan konsisten.
Konrad Rudolph
6
@BT Saya pikir Anda berasumsi bahwa contoh saya dari alur kerja yang lebih nyaman adalah alasan di balik keputusan tersebut. Bukan, itu hanya konsekuensi. The Alasan adalah bahwa aturan POSIX adalah aturan yang paling sederhana, dan yang membuat penanganan baris dalam parser yang paling mudah. Satu-satunya alasan kita bahkan memiliki perdebatan adalah bahwa Windows melakukannya secara berbeda, dan sebagai konsekuensinya, ada banyak alat yang gagal pada file POSIX. Jika semua orang melakukan POSIX, tidak akan ada masalah. Namun orang mengeluh tentang POSIX, bukan tentang Windows.
Konrad Rudolph
7
@ Bt Saya hanya merujuk ke Windows untuk menunjukkan kasus-kasus di mana aturan POSIX tidak masuk akal (dengan kata lain, saya melemparkan Anda tulang). Saya sangat senang tidak pernah menyebutkannya dalam diskusi ini lagi. Tetapi kemudian klaim Anda menjadi semakin tidak masuk akal: pada platform POSIX tidak masuk akal untuk mendiskusikan file teks dengan konvensi akhir baris yang berbeda, karena tidak ada alasan untuk memproduksinya. Apa untungnya? Secara harfiah tidak ada. - Singkatnya, saya benar - benar tidak mengerti kebencian yang dijawab oleh jawaban ini (atau aturan POSIX). Sejujurnya, itu sama sekali tidak rasional.
Konrad Rudolph
282

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.

Standar bahasa C mengatakan file sumber yang tidak kosong harus diakhiri dengan karakter baris baru, yang tidak akan segera didahului oleh karakter backslash.

Karena ini adalah klausa "wajib", kita harus memancarkan pesan diagnostik untuk pelanggaran aturan ini.

Ini ada di bagian 2.1.1.2 dari standar ANSI C 1989. Bagian 5.1.1.2 dari standar ISO C 1999 (dan mungkin juga standar ISO C 1990).

Referensi: Arsip surat GCC / GNU .

Bill the Lizard
sumber
17
tolong tulis program yang bagus kemudian yang memungkinkan untuk menyisipkan baris baru itu di mana diperlukan saat memproses atau mampu menangani yang "hilang" dengan benar ... yang, pada kenyataannya, tidak hilang
tobibeer
4
@BilltheLizard, Apa beberapa contoh "Beberapa program memiliki masalah dalam memproses baris terakhir file jika tidak dihentikan baris baru" ?
Pacerier
4
@Pacerier wc -ltidak akan menghitung baris terakhir file jika bukan baris baru dihentikan. Juga, catakan 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.
Bill the Lizard
2
@BilltheLizard, maksud saya wctelah telah disebutkan ....
Pacerier
2
@ BilltheLizard, My bad, untuk mengklarifikasi: apa saja contoh program yang memiliki masalah memproses baris terakhir file jika tidak baris baru dihentikan (selain yang telah secara massal disebutkan di utas seperti catdan wc)?
Pacerier
116

Jawaban ini merupakan upaya jawaban teknis daripada pendapat.

Jika kita ingin menjadi purix POSIX, kita mendefinisikan sebuah baris sebagai:

Urutan nol atau lebih karakter <newline> plus karakter terminasi <newline>.

Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

Baris tidak lengkap sebagai:

Urutan satu atau lebih karakter bukan <newline> di akhir file.

Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

File teks sebagai:

File yang berisi karakter yang disusun dalam nol atau lebih baris. Baris tidak mengandung karakter NUL dan panjangnya tidak boleh melebihi {LINE_MAX} byte, termasuk karakter <newline>. Meskipun POSIX.1-2008 tidak membedakan antara file teks dan file biner (lihat standar ISO C), banyak utilitas hanya menghasilkan output yang dapat diprediksi atau bermakna ketika beroperasi pada file teks. Utilitas standar yang memiliki batasan seperti itu selalu menentukan "file teks" di bagian STDIN atau INPUT FILES.

Sumber: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

Sebuah string sebagai:

Urutan byte yang berdekatan diakhiri oleh dan termasuk byte nol pertama.

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 wcmanual yang kita baca:

Baris didefinisikan sebagai string karakter yang dibatasi oleh karakter <newline>.

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.

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

Perhatikan catukuran 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 catdua file yang outputnya menjadi hanya satu baris, bukan dua? Dengan kata lain, catlakukan apa yang seharusnya dilakukan.

Satu man- catsatunya menyebutkan input pembacaan hingga EOF, bukan <newline>. Perhatikan bahwa -nsaklar catjuga akan mencetak garis yang diakhiri non-<newline> (atau garis tidak lengkap ) sebagai garis - artinya penghitungan dimulai dari 1 (sesuai dengan man.)

-n Beri nomor pada garis keluaran, mulai dari 1.

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 filenamesatu dapat melakukannya awk '{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, kami curld) - 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.

Milan Adamovsky
sumber
2
POSIX tidak ditandai dalam pertanyaan ... bagaimana dengan akhir jalur MVS / OS? atau ujung garis MS-DOS? Ngomong-ngomong, semua sistem posix yang dikenal memungkinkan file teks tanpa akhir baris akhir (tidak ada kasus dari sistem klaim yang sesuai dengan posix di mana "file teks" memiliki perlakuan khusus di kernel untuk memasukkan baris baru yang tepat jika tidak ada baris baru) it)
Luis Colorado
62

Ini mungkin terkait dengan perbedaan antara :

  • file teks (setiap baris seharusnya diakhiri dengan end-of-line)
  • file biner (tidak ada "baris" yang benar untuk dibicarakan, dan panjang file harus dipertahankan)

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:

1 first line
2 middle line
3 last line
4
VONC
sumber
11
+1. Saya telah menemukan pertanyaan SO ini saat mengalami masalah ini. Hal ini sangat menjengkelkan Eclipse untuk menunjukkan ini "palsu" baris terakhir, dan Jika saya keluarkan, kemudian git (dan semua alat unix lain yang berharap EOL) mengeluh. Juga, perhatikan bahwa ini bukan hanya di tahun 2005: Eclipse 4.2 Juno masih memiliki masalah ini.
MestreLion
@MestreLion, Lanjutan di stackoverflow.com/questions/729692/…
Pacerier
46

Beberapa alat mengharapkan ini. Misalnya, wcmengharapkan ini:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
Flimm
sumber
22
Saya tidak akan mengatakan "beberapa", saya katakan sebagian besar alat mengharapkan itu untuk file teks, jika tidak semua. kucing, git, diff, wc, grep, sed ... daftarnya sangat besar
MestreLion
Mungkin orang bisa mengatakan itu wctidak mengharapkan ini, sebanyak itu hanya bekerja dalam definisi POSIX dari "garis" yang bertentangan dengan pemahaman intuitif kebanyakan orang tentang "garis".
Guildenstern
@Guildenstern Definisi intuitif untuk wc -lmencetak 1dalam kedua kasus, tetapi beberapa orang mungkin mengatakan kasus kedua harus dicetak 2.
Flimm
@ Flimm Jika Anda menganggap \nsebagai terminator garis, bukan sebagai pemisah garis, seperti POSIX / UNIX, maka mengharapkan case kedua untuk mencetak 2 benar-benar gila.
titik koma
21

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"

cgp
sumber
5
GCC tidak mampu memproses file, ia harus memberikan peringatan sebagai bagian dari standar C.
Bill the Lizard
IIRC, MSVC 2005 mengeluh tentang file C yang berakhir dengan baris tidak lengkap dan mungkin menolak untuk mengkompilasinya.
Mark K Cowan
16

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.

Stefan
sumber
15
Saat ini baris baru di EOF untuk file teks mungkin bukan keharusan, tetapi ini adalah konvensi yang berguna yang membuat sebagian besar alat unix bekerja bersama dengan hasil yang konsisten. Itu sama sekali bukan bug.
MestreLion
14
Banyak dari kita tidak menggunakan alat Unix sama sekali, dan kami tidak peduli.
DaveWalley
12
Ini bukan hanya alat unix, alat apa pun akan bekerja lebih baik dan / atau dikodekan lebih sederhana jika dapat mengasumsikan format file yang masuk akal.
Sam Watkins
2
@ Sam Watkins Setuju memiliki format sederhana yang didefinisikan dengan baik adalah baik. Namun kode masih perlu kebenaran, dan tidak berasumsi, data sesuai format.
chux - Reinstate Monica
8
@MestreLion Ini adalah warisan yang tidak berguna dari seperangkat alat buruk yang sesuai dengan standar bodoh. Artefak pemrograman ekstremis ini (yaitu file semuanya! Semuanya harus berbicara teks biasa!) Tidak mati segera setelah penemuan mereka karena mereka adalah satu-satunya alat yang tersedia dari jenis itu pada saat tertentu dalam sejarah. C digantikan oleh C ++, ini bukan bagian dari POSIX, tidak membutuhkan EOL di EOF, dan penggunaannya (jelas) tidak disarankan oleh * nix luddists.
polkovnikov.ph
14

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 blameing file untuk mengetahui kapan baris itu terakhir diedit akan menampilkan tambahan teks, bukan komit sebelum yang Anda benar-benar ingin lihat.

Robin Whittleton
sumber
1
diff dan menyalahkan seharusnya hanya diperbarui untuk mendeteksi "baris baru" daripada "baris baru" ( \n). Masalah terpecahkan.
Andrew
1
Anda dapat menggunakan tag -w untuk mengabaikan perubahan spasi putih, tetapi itu bukan default.
Robin Whittleton
11

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:

  1. Karena itulah cara POSIX mendefinisikannya.
  2. Karena beberapa alat mengharapkannya atau "berperilaku buruk" tanpanya. Misalnya, wc -ltidak akan menghitung "garis" akhir jika tidak diakhiri dengan baris baru.
  3. Karena itu sederhana dan nyaman. Di Unix, cathanya berfungsi dan bekerja tanpa komplikasi. Itu hanya menyalin byte dari setiap file, tanpa perlu interpretasi. Saya tidak berpikir ada setara dengan DOS cat. Menggunakan copy a+b cakan berakhir dengan menggabungkan baris terakhir file adengan baris pertama fileb .
  4. Karena file (atau aliran) dari garis nol dapat dibedakan dari file dari satu baris kosong.
jrw32982 mendukung Monica
sumber
11

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.

simbion
sumber
10

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 ...

Marc Gravell
sumber
12
Ini bukan aturan, itu adalah konvensi: sebuah garis adalah sesuatu yang berakhir dengan garis akhir . Jadi tidak, tidak ada "baris akhir kosong" antara EOL dan EOF.
MestreLion
4
@MestreLion: Tetapi karakter yang dimaksud tidak bernama "end-of-line", itu bernama "newline" dan / atau "linefeed". Pemisah garis, bukan terminator garis. Dan hasilnya ADALAH garis kosong terakhir.
Ben Voigt
2
Tidak ada alat (waras) akan menghitung EOL (CR, LF, dll) terakhir dari file sebagai tambahan, baris kosong. Dan semua alat POSIX tidak akan menghitung karakter terakhir dari suatu file sebagai baris jika tidak ada akhiran EOL. Terlepas dari nama karakter EOL yang menjadi "umpan baris" atau "carriage return" (tidak ada karakter bernama "baris baru"), untuk semua alat praktis yang masuk akal, perlakukan sebagai terminator garis , bukan sebagai pemisah garis .
MestreLion
2
@MestreLion, Apakah Anda yakin "terminator garis" waras? Ambil beberapa yang bukan programmer dan lakukan survei cepat. Anda akan segera menyadari konsep garis lebih dekat dengan konsep "pemisah garis". Konsep "line terminator" memang aneh .
Pacerier
4
@ Sahuagin: Ini bukan pandangan saya , beginilah Standar POSIX mendefinisikan sebuah garis. File kosong dengan 0 byte memiliki 0 baris, maka tidak ada EOL, dan file yang dianggap hanya memiliki satu baris kosong, memang membutuhkan EOL. Juga perhatikan ini hanya relevan jika Anda ingin menghitung baris pada file, karena jelas setiap editor akan membiarkan Anda "mendapatkan" ke baris berikutnya (atau yang pertama) terlepas dari apakah sudah ada EOL di sana.
MestreLion
10

Ada juga masalah pemrograman praktis dengan file yang tidak memiliki baris baru di akhir: readBash built-in (saya tidak tahu tentang readimplementasi lain ) tidak berfungsi seperti yang diharapkan:

printf $'foo\nbar' | while read line
do
    echo $line
done

Ini hanyafoo mencetak ! Alasannya adalah ketika readmenemukan baris terakhir, ia menulis konten $linetetapi mengembalikan kode 1 karena mencapai EOF. Ini memutus whileperulangan, jadi kami tidak pernah mencapai echo $linebagian itu. Jika Anda ingin menangani situasi ini, Anda harus melakukan hal berikut:

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')

Yaitu, lakukan echojika readgagal 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.

l0b0
sumber
9

Mengapa file (teks) harus diakhiri dengan baris baru?

Seperti yang diungkapkan oleh banyak orang, karena:

  1. Banyak program tidak berperilaku baik, atau gagal tanpanya.

  2. 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.

  3. Program jarang melarang final '\n'(saya tidak tahu ada).


Namun ini menimbulkan pertanyaan berikutnya:

Apa yang harus dilakukan kode tentang file teks tanpa baris baru?

  1. 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:

    // 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
      ...
    }
    
  2. 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.

  3. Tentukan dengan jelas, dokumentasikan, penanganan kode dari final yang hilang '\n'.

  4. Jangan, sesering mungkin, menghasilkan file yang tidak memiliki akhir '\n'.

chux - Pasang kembali Monica
sumber
4

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 seddansed 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.txtdengan beberapa jsonkonten di dalamnya.

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here

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 sedperintahsed 's|value|newValue|g' foo.txt > foo.txt.tmp

File yang baru dibuat adalah

[{
    someProp: value
},
{
    someProp: value

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.

Arpit
sumber
3

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.

he_the_great
sumber
0

Bayangkan file sedang diproses sementara file masih dibuat oleh proses lain.

Mungkin itu ada hubungannya dengan itu? Bendera yang menunjukkan bahwa file siap diproses.

Pippen_001
sumber
-4

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.

Pengguna
sumber
-6

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.

Torben Gundtofte-Bruun
sumber