Saya ingin menghapus spasi kosong dari semua file dalam hierarki direktori rekursif. Saya menggunakan ini:
find * -type f -exec sed 's/[ \t]*$//' -i {} \;
Ini berfungsi, tetapi juga akan menghapus jejak "spasi putih" dari file biner yang ditemukan, yang tidak diinginkan.
Bagaimana saya tahu find
untuk menghindari menjalankan perintah ini pada file biner?
file
yang dapat memeriksa data.Jawaban:
Anda dapat mencoba menggunakan
file
perintah Unix untuk membantu mengidentifikasi file yang tidak Anda inginkan, tetapi saya pikir mungkin lebih baik jika Anda secara eksplisit menentukan file apa yang ingin Anda tekan daripada yang tidak Anda inginkan.untuk menghindari melintasi ke file kontrol sumber Anda mungkin ingin sesuatu seperti
Anda mungkin perlu atau tidak membutuhkan beberapa garis miring terbalik tergantung pada cangkang Anda.
sumber
-i
opsi untuk sed . Sulit untuk menulis perintah shell portabel, bukan?Itu bisa dilakukan di baris perintah.
sumber
Jawaban paling sederhana dan paling portabel adalah menjalankan ini:
Saya menjelaskan mengapa di bawah ini, di mana saya juga menunjukkan bagaimana melakukannya hanya dengan menggunakan baris perintah, serta bagaimana menangani file teks trans-ASCII seperti ISO-8859-1 (Latin-1) dan UTF-8, yang sebelumnya tidak memiliki Ruang putih-ASCII di dalamnya.
Sisa dari Kisah
Masalahnya adalah bahwa find (1) tidak mendukung
-T
operator filetest, juga tidak mengenali pengkodean jika itu - yang Anda benar-benar perlu mendeteksi UTF-8, pengkodean Unicode standar de facto standar.Yang bisa Anda lakukan adalah menjalankan daftar nama file melalui lapisan yang membuang file biner. Sebagai contoh
Namun sekarang Anda memiliki masalah dengan spasi putih di nama file Anda, jadi Anda harus mengakhiri ini dengan penghentian nol:
Hal lain yang bisa Anda lakukan adalah menggunakan
find
tetapifind2perl
, karena Perl-T
sudah mengerti :Dan jika Anda ingin Perl menganggap file-nya berada di UTF-8, gunakan
Atau Anda dapat menyimpan skrip yang dihasilkan dalam file dan mengeditnya. Anda benar-benar benar-benar tidak boleh hanya menjalankan
-T
filetest pada file lama apa pun, tetapi hanya pada mereka yang file biasa seperti yang pertama kali ditentukan oleh-f
. Kalau tidak, Anda berisiko membuka spesial perangkat, memblokir fifos, dll.Namun, jika Anda akan melakukan semua itu, Anda mungkin melewatkan sed (1) sama sekali. Untuk satu hal, ini lebih portabel, karena versi POSIX sed (1) tidak mengerti
-i
, sedangkan semua versi Perl lakukan. Versi terakhir dari sed dengan penuh kasih sayang menggunakan opsi yang sangat berguna-i
dari Perl tempat saya pertama kali muncul.Ini juga memberi Anda kesempatan untuk memperbaiki regex Anda juga. Anda harus benar-benar menggunakan pola yang cocok dengan satu atau lebih spasi spasi horizontal, tidak hanya nol, atau Anda akan berjalan lebih lambat dari penyalinan yang tidak perlu. Yaitu, ini:
seharusnya
Namun, bagaimana untuk sed (1) untuk memahami yang membutuhkan ekstensi-POSIX non, biasanya baik
-R
untuk Sistem Ⅴ beragam Unix seperti Solaris atau Linux, atau-E
untuk yang BSD seperti OpenBSD atau MacOS. Saya menduga itu tidak mungkin di bawah AIX. Sayangnya, lebih mudah menulis shell portabel daripada skrip shell portabel.Peringatan pada 0xA0
Walaupun itu adalah satu-satunya karakter spasi putih horizontal di ASCII, ISO-8859-1 dan juga Unicode memiliki ruang NO-BREAK pada titik kode U + 00A0. Ini adalah salah satu dari dua karakter non-ASCII teratas yang ditemukan di banyak Unicode corpora, dan akhir-akhir ini saya melihat banyak kode regex orang rusak karena mereka lupa.
Jadi kenapa tidak Anda lakukan saja ini:
Jika Anda mungkin memiliki UTF-8 file untuk menangani, add
-CSD
, dan jika Anda menjalankan Perl v5.10 atau lebih, Anda dapat menggunakan\h
untuk spasi horizontal dan\R
untuk linebreak generik, yang meliputi\r
,\n
,\r\n
,\f
,\cK
,\x{2028}
, dan\x{2029}
:Itu akan bekerja pada semua file UTF-8 tidak peduli linebreak mereka, menghilangkan spasi spasi horizontal (properti karakter Unicode
HorizSpace
) termasuk spasi NO-BREAK SPEAK yang terjadi sebelum linebreak Unicode (termasuk CRLF combo) di akhir setiap baris.Ini juga jauh lebih portabel daripada versi sed (1), karena hanya ada satu perl (1) implementasi, tetapi banyak sed (1).
Masalah utama yang saya lihat masih ada di sana adalah dengan find (1), karena pada beberapa sistem yang benar-benar bandel (Anda tahu siapa Anda, AIX dan Solaris), ia tidak akan memahami
-print0
arahan superkritis . Jika itu situasi Anda, maka Anda harus menggunakanFile::Find
modul dari Perl secara langsung, dan tidak menggunakan utilitas Unix lainnya. Ini adalah versi Perl murni dari kode Anda yang tidak bergantung pada hal lain:Jika Anda menjalankan hanya pada file teks ASCII atau ISO-8859-1, itu bagus, tetapi jika Anda menjalankan dengan file ASCII atau UTF-8, tambahkan
-CSD
ke switch di panggilan interior ke Perl.Jika Anda memiliki penyandian campuran dari ketiga ASCII, ISO-8859-1, dan UTF-8, maka saya khawatir Anda memiliki masalah lain. :( Anda harus mencari tahu penyandian berdasarkan per-file, dan tidak pernah ada cara yang baik untuk menebaknya.
Ruang Putih Unicode
Sebagai catatan, Unicode memiliki 26 karakter spasi yang berbeda. Anda dapat menggunakan yang unichars utilitas untuk mengendus keluar ini. Hanya tiga karakter spasi horisontal pertama yang hampir pernah terlihat:
sumber
GNU grep cukup bagus dalam mengidentifikasi apakah suatu file biner atau tidak. Selain Solaris, saya yakin ada platform lain yang tidak datang dengan GNU grep terinstal secara default, tetapi seperti Solaris, saya yakin Anda dapat menginstalnya.
Jika Anda berada di Solaris, Anda akan menggantinya
grep
dengan/opt/csw/bin/ggrep
.The
grep
bendera melakukan hal berikut:l
hanya daftar nama file untuk file yang cocok,R
adalah rekursif,I
cocok hanya file text (mengabaikan file biner), danP
bagi sintaks ekspresi reguler perl-kompatibel.Bagian perl memodifikasi file di tempat, menghapus semua spasi tambahan / tab.
Terakhir: jika UTF8 merupakan suatu masalah, jawaban tchrist yang digabungkan dengan milik saya harus mencukupi, asalkan build yang
grep
Anda miliki dibangun dengan dukungan UTF8 (biasanya pengelola paket mencoba menyediakan fungsionalitas semacam itu).sumber