Pertanyaan Mengapa file teks harus diakhiri dengan baris baru?


Saya berasumsi semua orang di sini akrab dengan pepatah bahwa semua file teks harus diakhiri dengan baris baru. Saya sudah tahu "aturan" ini selama bertahun-tahun tetapi saya selalu bertanya-tanya - mengapa?


1090
2018-04-08 12:16


asal


Jawaban:


Karena itu bagaimana standar POSIX mendefinisikan a garis:

3.206 Line
Urutan nol atau lebih karakter non- <newline> plus karakter <newline> terminating.

Oleh karena itu, garis yang tidak berakhir pada karakter baris baru tidak dianggap garis sebenarnya. Itu sebabnya beberapa program mengalami masalah saat memproses baris terakhir file jika bukan jalur baru yang dihentikan.

Setidaknya ada satu keuntungan yang sulit untuk panduan 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 *.txt
foobar
baz

Dan, seperti contoh sebelumnya juga menunjukkan, ketika menampilkan file pada baris perintah (mis. Via more), file yang diakhiri newline menghasilkan tampilan yang benar. File yang dihentikan secara tidak benar dapat menjadi kacau (baris kedua).

Untuk konsistensi, sangat membantu untuk mengikuti aturan ini - dengan melakukan hal sebaliknya akan menimbulkan pekerjaan tambahan ketika berhadapan dengan alat Unix default.

Sekarang non POSIX compliant sistem (saat ini kebanyakan Windows), intinya diperdebatkan: file umumnya tidak berakhir dengan baris baru, dan definisi (informal) dari suatu baris misalnya adalah "teks yang dipisahkan oleh baris baru ”(perhatikan penekanannya). Ini sepenuhnya valid. Namun, untuk data terstruktur (misalnya kode pemrograman), proses pembuatannya menjadi lebih sedikit rumit: biasanya berarti bahwa parser harus ditulis ulang. Jika parser awalnya ditulis dengan definisi POSIX dalam pikiran, maka mungkin lebih mudah untuk memodifikasi aliran token daripada parser - dengan kata lain, tambahkan token "artificial newline" ke ujung input.


1021
2018-04-08 12:46



Setiap baris harus diakhiri dengan karakter baris baru, termasuk yang terakhir. Beberapa program mengalami masalah saat memproses baris terakhir file jika bukan jalur baru yang dihentikan.

GCC memperingatkan tentang hal itu bukan karena itu tidak bisa 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 "harus", 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.


245
2018-04-08 12:26



Jawaban ini merupakan upaya jawaban teknis daripada pendapat.

Jika kita ingin menjadi POSIX purist, kita mendefinisikan garis sebagai:

Urutan nol atau lebih karakter non- <newline> plus karakter <newline> terminating.

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

Baris tidak lengkap sebagai:

Urutan satu atau beberapa karakter non-<newline> di akhir file.

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

File teks sebagai:

File yang berisi karakter diatur ke dalam nol atau lebih banyak baris. Garis tidak mengandung karakter NUL dan tidak dapat melebihi panjang {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 keluaran yang dapat diprediksi atau berarti ketika beroperasi pada file teks. Utilitas standar yang memiliki pembatasan tersebut selalu menentukan "file teks" di bagian STDIN atau INPUT FILES.

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

String sebagai:

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

Sumber: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

Dari ini, kita dapat memperoleh bahwa satu-satunya waktu kita akan melakukannya berpotensi menghadapi segala jenis masalah jika kita berurusan dengan konsep a garis file atau file sebagai file teks (menjadi itu a file teks adalah organisasi dari nol atau lebih garis, dan garis yang kita tahu harus diakhiri dengan <newline>).

Inti masalah: wc -l filename.

Dari wcmanual yang kami baca:

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

Apa implikasinya terhadap file JavaScript, HTML, dan CSS kemudian adalah bahwa mereka teks  file?

Di browser, IDE modern, dan aplikasi front-end lainnya tidak ada masalah dengan melewatkan EOL di EOF. Aplikasi akan mem-parse file dengan benar. Karena tidak semua Sistem Operasi sesuai dengan standar POSIX, jadi tidak praktis untuk alat non-OS (misalnya browser) untuk menangani file sesuai dengan standar POSIX (atau standar tingkat OS).

Sebagai hasilnya, kita dapat secara relatif yakin bahwa EOL di EOF akan hampir tidak berdampak 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 aman ketika berhadapan dengan JS, HTML, CSS di sisi-klien. Sebenarnya, kita dapat menyatakan bahwa mengecilkan salah satu dari file-file ini, yang tidak mengandung <newline> aman.

Kita dapat mengambil langkah satu ini lebih jauh dan mengatakan bahwa sejauh NodeJS prihatin juga tidak dapat mematuhi standar POSIX yang dapat dijalankan di lingkungan yang tidak mendukung POSIX.

Lalu kita pergi dengan apa? Tooling tingkat sistem.

Ini berarti satu-satunya masalah yang mungkin timbul adalah dengan alat yang berusaha untuk mengamalkan fungsionalitasnya ke semantik POSIX (misalnya definisi garis seperti yang ditunjukkan di wc).

Meski begitu, tidak semua shell akan secara otomatis mematuhi POSIX. Bash misalnya tidak default ke perilaku POSIX. Ada tombol untuk mengaktifkannya: POSIXLY_CORRECT.

Makanan untuk berpikir tentang nilai EOL menjadi <newline>: http://www.rfc-editor.org/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 tulisan ini file dalam contoh ini adalah JavaScript yang sudah dikecilkan 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 cat ukuran file adalah jumlah dari masing-masing bagiannya. Jika rangkaian file JavaScript merupakan perhatian untuk file JS, kekhawatiran yang lebih tepat adalah memulai setiap file JavaScript dengan titik koma.

Seperti orang lain yang disebutkan di utas ini: bagaimana jika Anda mau cat dua file yang hasilnya hanya menjadi satu baris, bukan dua? Dengan kata lain, cat melakukan apa yang seharusnya dilakukan.

Itu man dari cat hanya menyebutkan membaca masukan hingga EOF, bukan <newline>. Perhatikan bahwa -n beralih dari cat juga akan mencetak baris non-<newline> yang dihentikan (atau baris tidak lengkap) sebagai garis - karena itu hitungan dimulai 1 (Menurut man.)

-nNomor baris output, mulai dari 1.

Sekarang kita mengerti bagaimana POSIX mendefinisikan a garis , perilaku ini menjadi ambigu, atau benar-benar, tidak patuh.

Memahami tujuan dan kepatuhan alat tertentu akan membantu dalam menentukan seberapa penting untuk mengakhiri file dengan EOL. Di 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 yang bisa dilakukan awk '{x++}END{ print x}' filename , dan yakinlah bahwa keberhasilan tugas tersebut tidak terancam oleh file yang mungkin ingin kami proses yang tidak kami tulis (mis. pustaka pihak ketiga seperti JS kami yang diperkecil curld) - kecuali niat kami benar-benar dihitung garis dalam arti kepatuhan POSIX.

Kesimpulan

Akan ada sangat sedikit kasus penggunaan kehidupan nyata di mana melewatkan EOL di EOF untuk file teks tertentu seperti JS, HTML, dan CSS akan berdampak negatif - jika sama sekali. Jika kami mengandalkan <newline> saat ini, kami membatasi keandalan alat kami hanya pada file yang kami penulis dan membuka diri terhadap potensi kesalahan yang diperkenalkan oleh file pihak ketiga.

Moral dari cerita: tooler Engineer yang tidak memiliki kelemahan mengandalkan EOL di EOF.

Jangan ragu untuk memposting kasus penggunaan karena mereka berlaku untuk JS, HTML dan CSS di mana kita dapat memeriksa bagaimana melewatkan EOL memiliki efek buruk.


87
2017-08-15 06:31



Ini mungkin terkait dengan perbedaan antara:

  • file teks (setiap baris seharusnya berakhir di akhir-of-line)
  • file biner (tidak ada "garis" yang benar untuk dibicarakan, dan panjang file harus dipertahankan)

Jika setiap baris berakhir di akhir baris, ini menghindari, misalnya, bahwa menggabungkan dua file teks akan membuat baris terakhir dari larik pertama ke baris pertama dari baris kedua.

Plus, editor dapat memeriksa apakah file berakhir di akhir baris, menyimpannya dalam 'eol' pilihan lokal, dan menggunakannya saat menulis file.

Beberapa tahun yang lalu (2005), banyak editor (ZDE, Eclipse, Scite, ...) yang "lupa" pada EOL terakhir, yang tidak begitu dihargai.
Tidak hanya itu, tetapi mereka menafsirkan EOL akhir yang salah, sebagai 'memulai 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 yang sebenarnya. Anda melihat sesuatu seperti ini:

1 first line
2 middle line
3 last line
4

59
2018-04-08 12:29



Beberapa alat mengharapkan ini. Sebagai contoh, wc mengharapkan ini:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1

37
2017-10-12 14:16



Pada dasarnya ada banyak program yang tidak akan memproses file dengan benar jika mereka tidak mendapatkan EID EOL terakhir.

GCC memperingatkan Anda tentang ini karena diharapkan sebagai bagian dari standar C. (Bagian 5.1.1.2 rupanya)

"Tidak ada baris baru pada akhir file" peringatan kompilator


18
2018-04-08 12:21



Ini berasal dari hari-hari awal ketika terminal sederhana digunakan. Char baris baru digunakan untuk memicu 'flush' dari data yang ditransfer.

Hari ini, char newline tidak diperlukan lagi. Tentu, banyak aplikasi masih mengalami masalah jika baris baru tidak ada di sana, tetapi saya akan menganggap bahwa bug di aplikasi tersebut.

Namun jika Anda memiliki format file teks di mana Anda memerlukan newline, Anda mendapatkan verifikasi data sederhana yang sangat murah: jika file diakhiri dengan baris yang tidak memiliki baris baru di akhir, Anda tahu file tersebut rusak. Dengan hanya satu byte tambahan untuk setiap baris, Anda dapat mendeteksi file yang rusak dengan akurasi tinggi dan hampir tidak ada waktu CPU.


12
2018-04-08 12:41



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

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

Cetakan ini hanya foo! Alasannya adalah kapan read bertemu dengan baris terakhir, ia menulis isinya $line tetapi mengembalikan kode keluar 1 karena mencapai EOF. Ini merusak while loop, jadi kami tidak pernah mencapai echo $line bagian. Jika Anda ingin menangani situasi ini, Anda harus melakukan hal-hal berikut:

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

Yaitu, lakukan echo jika read gagal karena baris tidak kosong di akhir file. Tentu saja, dalam hal ini akan ada satu tambahan baris baru dalam output yang tidak di input.


10
2017-11-04 10:12