Menggunakan sistem kontrol versi, saya merasa terganggu pada suara ketika diff mengatakan No newline at end of file
.
Jadi saya bertanya-tanya: Bagaimana cara menambahkan baris baru di akhir file untuk menghilangkan pesan-pesan itu?
bash
shell
text-processing
newlines
k0pernikus
sumber
sumber
Jawaban:
Untuk membersihkan proyek secara rekursif, saya menggunakan oneliner ini:
Penjelasan:
git ls-files -z
daftar file dalam repositori. Dibutuhkan pola opsional sebagai parameter tambahan yang mungkin berguna dalam beberapa kasus jika Anda ingin membatasi operasi ke file / direktori tertentu. Sebagai alternatif, Anda bisa menggunakanfind -print0 ...
atau program serupa untuk membuat daftar file yang terkena dampak - pastikan saja ia memancarkanNUL
entri yang telah direvisi.while IFS= read -rd '' f; do ... done
iterates melalui entri, aman menangani nama file yang menyertakan spasi dan / atau baris baru.tail -c1 < "$f"
membaca char terakhir dari sebuah file.read -r _
keluar dengan status keluar bukan nol jika baris baru tertinggal tidak ada.|| echo >> "$f"
menambahkan baris baru ke file jika status keluar dari perintah sebelumnya adalah nol.sumber
find -name \*.java | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
git ls-files
yang masih akan menyelamatkan Anda dari mengedit file yang tidak dilacak dalam kontrol versi.IFS=
untuk mengeset separator baik untuk melestarikan spasi putih sekitarnya. Entri yang dihentikan nol hanya relevan jika Anda memiliki file atau direktori dengan baris baru di namanya, yang sepertinya agak dibuat-buat, tetapi cara yang lebih tepat untuk menangani kasus generik, saya setuju. Sama seperti peringatan kecil:-d
opsi untukread
tidak tersedia di POSIX sh.tail -n1 < "$f"
untuk menghindari masalah dengan nama file yang dimulai dengan-
(tail -n1 -- "$f"
tidak berfungsi untuk file yang dipanggil-
). Anda mungkin ingin mengklarifikasi bahwa jawabannya sekarang khusus zsh / bash.Ini dia :
Dan sebagai alternatif untuk OS X
sed
:Ini menambahkan
\n
di akhir file hanya jika belum diakhiri dengan baris baru. Jadi, jika Anda menjalankannya dua kali, itu tidak akan menambah baris baru:sumber
man sed
:$ Match the last line.
Tapi mungkin itu hanya bekerja secara tidak sengaja. Solusi Anda juga berfungsi.$
cocok dengan baris terakhir, mengapa tidak menambahkan baris baru ke string yang sudah berisi baris baru?$
. Di dalam regex, seperti dengan formulir/<regex>/
, itu memiliki makna "cocok ujung garis" yang biasa. Kalau tidak, digunakan sebagai alamat, sed memberikan makna "baris terakhir dalam file" khusus. Kode berfungsi karena sed secara default menambahkan baris baru ke outputnya jika belum ada. Kode "$ a \" hanya mengatakan "cocok dengan baris terakhir file, dan tidak menambahkan apa pun ke dalamnya." Tetapi secara implisit, sed menambahkan baris baru ke setiap baris yang diprosesnya (seperti$
baris ini ) jika belum ada di sana./regex/
memberinya makna yang berbeda. Halaman manual FreeBSD sedikit lebih informatif, saya pikir: freebsd.org/cgi/man.cgi?query=sedLihat:
jadi
echo "" >> noeol-file
sebaiknya lakukan triknya. (Atau apakah Anda bermaksud meminta untuk mengidentifikasi file-file ini dan memperbaikinya?)edit menghapus
""
dariecho "" >> foo
(lihat komentar @ yuyichao) edit2 menambahkan""
lagi ( tapi lihat komentar @Keith Thompson)sumber
""
tidak diperlukan (setidaknya untuk bash) dantail -1 | wc -l
dapat digunakan untuk mengetahui file tanpa baris baru di akhir""
perlu untuk bash, tapi saya telah melihatecho
implementasi yang tidak mencetak apa-apa ketika dipanggil tanpa argumen (meskipun tidak ada yang bisa saya temukan sekarang melakukan ini).echo "" >> noeol-file
mungkin sedikit lebih kuat.printf "\n" >> noeol-file
bahkan lebih dari itu.csh
'secho
adalah salah satu dikenal untuk output apa-apa bila tidak lulus argumen. Tapi kemudian jika kita akan mendukung kerang non-Bourne-seperti, kita harus membuatecho ''
bukanecho ""
sebagaiecho ""
akan ouput""<newline>
denganrc
ataues
misalnya.tcsh
, tidak seperticsh
, mencetak baris baru ketika dipanggil tanpa argumen - terlepas dari pengaturan$echo_style
.Solusi lain menggunakan
ed
. Solusi ini hanya memengaruhi baris terakhir dan hanya jika\n
tidak ada:Ini pada dasarnya berfungsi membuka file untuk diedit melalui skrip, skrip adalah
w
perintah tunggal , yang menulis file kembali ke disk. Ini didasarkan pada kalimat yang ditemukan died(1)
halaman manual ini:sumber
Cara sederhana, portabel, dan sesuai dengan POSIX untuk menambahkan baris akhir yang tidak ada ke file teks:
Pendekatan ini tidak perlu membaca seluruh file; itu hanya dapat mencari EOF dan bekerja dari sana.
Pendekatan ini juga tidak perlu membuat file temp di belakang Anda (mis. Sed -i), sehingga hardlink tidak terpengaruh.
echo menambahkan baris baru ke file hanya ketika hasil substitusi perintah adalah string yang tidak kosong. Perhatikan bahwa ini hanya dapat terjadi jika file tidak kosong dan byte terakhir bukan baris baru.
Jika byte terakhir dari file adalah baris baru, tail mengembalikannya, lalu perintahkan strip penggantinya; hasilnya adalah string kosong. Tes -n gagal dan gema tidak berjalan.
Jika file kosong, hasil substitusi perintah juga merupakan string kosong, dan sekali lagi gema tidak berjalan. Ini diinginkan, karena file kosong bukan file teks tidak valid, juga tidak setara dengan file teks tidak kosong dengan baris kosong.
sumber
yash
jika karakter terakhir dalam file adalah karakter multi-byte (misalnya di UTF-8 lokal), atau jika lokal adalah C dan byte terakhir dalam file memiliki bit set ke-8. Dengan shell lain (kecuali zsh), itu tidak akan menambahkan baris baru jika file berakhir dengan byte NUL (tapi sekali lagi, itu berarti input akan menjadi non-teks bahkan setelah baris baru ditambahkan).Tambahkan baris baru terlepas dari:
Berikut adalah cara untuk memeriksa apakah ada baris baru di bagian akhir sebelum menambahkannya, dengan menggunakan Python:
sumber
echo ""
tampaknya lebih kuat daripadaecho -n '\n'
. Atau Anda bisa menggunakanprintf '\n'
Solusi tercepat adalah:
Sangat cepat.
Pada file ukuran sedang
seq 99999999 >file
ini membutuhkan milidetik.Solusi lain membutuhkan waktu lama:
Bekerja di abu, bash, lksh, mksh, ksh93, attsh dan zsh tetapi tidak yash.
Semua solusi lain yang disajikan di sini mengubah timestamp file.
Jika Anda membutuhkan solusi portabel untuk yash (dan semua cangkang lain yang tercantum di atas), mungkin akan sedikit lebih rumit:
sumber
Cara tercepat untuk menguji apakah byte terakhir file adalah baris baru adalah dengan hanya membaca byte terakhir. Itu bisa dilakukan dengan
tail -c1 file
. Namun, cara sederhana untuk menguji apakah nilai byte adalah baris baru, tergantung pada penghapusan shell biasa dari garis baru di dalam ekspansi perintah gagal (misalnya) di yash, ketika karakter terakhir dalam file adalah UTF- 8 nilai.Cara shell yang benar, sesuai POSIX, semua (wajar) untuk menemukan apakah byte terakhir dari file adalah baris baru adalah dengan menggunakan xxd atau hexdump:
Kemudian, membandingkan output di atas
0A
akan memberikan tes yang kuat.Berguna untuk menghindari menambahkan baris baru ke file yang kosong.
File yang gagal memberikan karakter terakhir
0A
, tentu saja:Pendek dan manis. Ini membutuhkan sedikit waktu karena hanya membaca byte terakhir (seek to EOF). Tidak masalah jika file itu besar. Maka hanya tambahkan satu byte jika diperlukan.
Tidak perlu file temp atau digunakan. Tidak ada hardlink yang terpengaruh.
Jika tes ini dijalankan dua kali, itu tidak akan menambah baris baru.
sumber
xxd
atauhexdump
utilitas POSIX. Di toolchest POSIX, adaod -An -tx1
untuk mendapatkan nilai hex byte.Anda lebih baik memperbaiki editor pengguna yang terakhir mengedit file. Jika Anda adalah orang terakhir yang mengedit file - editor apa yang Anda gunakan, saya menebak teman teks ..?
sumber
emacs
tidak menambahkan baris baru di akhir file.(setq require-final-newline 'ask)
di dalam saya.emacs
Jika Anda hanya ingin dengan cepat menambahkan baris baru saat memproses beberapa jalur pipa, gunakan ini:
itu juga sesuai dengan POSIX.
Kemudian, tentu saja, Anda dapat mengarahkannya ke file.
sumber
cat file.csv | tr "\r" "\n" | { cat; echo; } | sed "/^[[:space:]]*$/d" | tail -n +2 | wc -l
Asalkan tidak ada null dalam input:
... akan cukup untuk selalu hanya menambahkan baris baru ke ujung ekor infile jika belum memilikinya. Dan itu hanya perlu membaca file input melalui satu waktu untuk memperbaikinya.
sumber
paste infile 1<> infile
malah perlu .Meskipun tidak langsung menjawab pertanyaan, berikut adalah skrip terkait yang saya tulis untuk mendeteksi file yang tidak diakhiri dengan baris baru. Ini sangat cepat.
Skrip perl membaca daftar nama file (secara opsional diurutkan) dari stdin dan untuk setiap file membaca byte terakhir untuk menentukan apakah file berakhir pada baris baru atau tidak. Ini sangat cepat karena menghindari membaca seluruh isi setiap file. Ini menghasilkan satu baris untuk setiap file yang dibacanya, diawali dengan "kesalahan:" jika beberapa jenis kesalahan terjadi, "kosong:" jika file kosong (tidak berakhir dengan baris baru!), "EOL:" ("akhir dari baris ") jika file berakhir dengan baris baru dan" tidak EOL: "jika file tidak berakhir dengan baris baru.
Catatan: skrip tidak menangani nama file yang berisi baris baru. Jika Anda menggunakan sistem GNU atau BSD, Anda dapat menangani semua nama file yang mungkin dengan menambahkan -print0 untuk menemukan, -z untuk mengurutkan, dan -0 ke perl, seperti ini:
Tentu saja, Anda masih harus menemukan cara untuk menyandikan nama file dengan baris baru di output (dibiarkan sebagai latihan untuk pembaca).
Keluaran dapat difilter, jika diinginkan, untuk menambahkan baris baru ke file-file yang tidak memilikinya, paling sederhana dengan
Kurangnya baris baru final dapat menyebabkan bug dalam skrip karena beberapa versi shell dan utilitas lain tidak akan menangani baris baru akhir yang hilang saat membaca file tersebut.
Dalam pengalaman saya, tidak adanya baris baru final disebabkan oleh penggunaan berbagai utilitas Windows untuk mengedit file. Saya belum pernah melihat vim menyebabkan baris baru yang hilang saat mengedit file, meskipun akan melaporkan file tersebut.
Akhirnya, ada skrip yang jauh lebih pendek (tetapi lebih lambat) yang dapat mengulangi input nama file mereka untuk mencetak file-file yang tidak berakhir pada baris baru, seperti:
sumber
The
vi
/vim
/ex
editor secara otomatis menambahkan<EOL>
di EOF kecuali file sudah memiliki itu.Jadi cobalah:
yang setara dengan:
Pengujian:
Untuk memperbaiki beberapa file, periksa: Bagaimana cara memperbaiki 'Tidak ada baris baru di akhir file' untuk banyak file? di SO
Mengapa ini sangat penting? Untuk menjaga agar file kami POSIX kompatibel .
sumber
Untuk menerapkan jawaban yang diterima ke semua file di direktori saat ini (plus subdirektori):
Ini berfungsi di Linux (Ubuntu). Pada OS X Anda mungkin harus menggunakan
-i ''
(belum diuji).sumber
find .
mencantumkan semua file, termasuk file dalam.git
. Untuk mengecualikan:find . -type f -not -path './.git/*' -exec sed -i -e '$a\' {} \;
Setidaknya dalam versi GNU, sederhanakan
grep ''
atauawk 1
dikanonikan inputnya, tambahkan baris baru akhir jika belum ada. Mereka memang menyalin file dalam proses, yang membutuhkan waktu jika besar (tapi sumbernya tidak boleh terlalu besar untuk dibaca?) Dan memperbarui modtime kecuali jika Anda melakukan sesuatu seperti(walaupun itu mungkin baik-baik saja pada file yang Anda periksa karena Anda memodifikasinya) dan kehilangan tautan, izin nondefault dan ACL dll kecuali Anda bahkan lebih berhati-hati.
sumber
grep '' file 1<> file
, meskipun itu masih akan membaca dan menulis file sepenuhnya.Ini bekerja di AIX ksh:
Dalam kasus saya, jika file tidak ada baris baru,
wc
perintah mengembalikan nilai2
dan kami menulis baris baru.sumber
Menambahkan ke jawaban Patrick Oscity , jika Anda hanya ingin menerapkannya ke direktori tertentu, Anda juga dapat menggunakan:
find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
Jalankan ini di dalam direktori yang Anda ingin tambahkan baris baru.
sumber
echo $'' >> <FILE_NAME>
akan menambahkan baris kosong ke akhir file.echo $'\n\n' >> <FILE_NAME>
akan menambahkan 3 baris kosong ke akhir file.sumber
Jika file Anda diakhiri dengan ujung jalur Windows
\r\n
dan Anda berada di Linux, Anda dapat menggunakansed
perintah ini . Itu hanya menambah\r\n
baris terakhir jika belum ada di sana:Penjelasan:
Jika baris terakhir sudah berisi
\r\n
maka pencarian regexp tidak akan cocok, maka tidak akan terjadi apa-apa.sumber
Anda dapat menulis
fix-non-delimited-line
skrip seperti:Bertentangan dengan beberapa solusi yang diberikan di sini, itu
Anda dapat menggunakannya misalnya sebagai:
atau:
POSIXly, Anda bisa melakukan sesuatu yang fungsionaly setara dengannya
sumber