Menggunakan awk untuk menghapus tanda urutan Byte

105

Bagaimana awkskrip (mungkin satu baris) untuk menghapus BOM terlihat seperti?

Spesifikasi:

  • cetak setiap baris setelah yang pertama ( NR > 1)
  • untuk baris pertama: Jika diawali dengan #FE #FFatau #FF #FE, hapus itu dan cetak sisanya
Boldewyn
sumber

Jawaban:

114

Coba ini:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' INFILE > OUTFILE

Pada rekaman pertama (baris), hapus karakter BOM. Cetak setiap rekaman.

Atau sedikit lebih pendek, menggunakan pengetahuan bahwa tindakan default di awk adalah mencetak data:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1' INFILE > OUTFILE

1 adalah kondisi terpendek yang selalu bernilai true, sehingga setiap record dicetak.

Nikmati!

- LAMPIRAN -

FAQ Unicode Byte Order Mark (BOM) menyertakan tabel berikut yang mencantumkan byte BOM yang tepat untuk setiap encoding:

Bytes         |  Encoding Form
--------------------------------------
00 00 FE FF   |  UTF-32, big-endian
FF FE 00 00   |  UTF-32, little-endian
FE FF         |  UTF-16, big-endian
FF FE         |  UTF-16, little-endian
EF BB BF      |  UTF-8

Dengan demikian, Anda dapat melihat seberapa \xef\xbb\xbfsesuai dengan EF BB BF UTF-8byte BOM dari tabel di atas.

Bartosz
sumber
1
Tampaknya titik di tengah sub pernyataan terlalu banyak (setidaknya, awk saya mengeluh tentang itu). Selain ini persis seperti yang saya cari, terima kasih!
Boldewyn
5
Solusi ini, bagaimanapun, hanya bekerja untuk file yang dikodekan UTF-8. Untuk yang lainnya, seperti UTF-16, lihat Wikipedia untuk representasi BOM yang sesuai: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn
2
Jadi: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILEdan pastikan INFILE dan OUTFILE berbeda!
Steve Clay
1
Jika Anda menggunakan perl -i.orig -pe 's/^\x{FFFE}//' badfileAnda bisa mengandalkan PERL_UNICODE dan / atau PERLIO envariabel untuk encoding. PERL_UNICODE = SD akan berfungsi untuk UTF-8; untuk yang lain, Anda membutuhkan PERLIO.
tchrist
1
Mungkin versi yang sedikit lebih pendek:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY
122

Menggunakan GNU sed(di Linux atau Cygwin):

# Removing BOM from all text files in current directory:
sed -i '1 s/^\xef\xbb\xbf//' *.txt

Di FreeBSD:

sed -i .bak '1 s/^\xef\xbb\xbf//' *.txt

Keuntungan menggunakan GNU atau FreeBSD sed: -iparameternya berarti "di tempat", dan akan memperbarui file tanpa perlu pengalihan atau trik aneh.

Di Mac:

awkSolusi ini di jawaban lain berfungsi , tetapi sedperintah di atas tidak berfungsi. Setidaknya pada seddokumentasi Mac (Sierra) tidak disebutkan dukungan pelolosan heksadesimal ala \xef.

Trik serupa dapat dicapai dengan program apa pun dengan menyalurkan ke spongealat dari moreutils :

awk '…' INFILE | sponge INFILE
Denilson Sá Maia
sumber
5
Saya mencoba perintah kedua tepatnya di Mac OS X dan hasilnya "berhasil", tetapi pergantian tidak benar-benar terjadi.
Trejkaz
1
Perlu dicatat bahwa perintah ini menggantikan satu urutan byte tertentu, yang merupakan salah satu tanda urutan byte yang mungkin . Mungkin file Anda memiliki urutan BOM yang berbeda. (Saya tidak bisa membantu selain itu, karena saya tidak punya Mac)
Denilson Sá Maia
3
Ketika saya mencoba perintah kedua di OS X pada file yang menggunakan 0xef 0xbb 0xbf sebagai BOM, sebenarnya tidak melakukan substitusi.
John Wiseman
Di OSX, saya hanya bisa menjalankan ini melalui perl, seperti yang ditunjukkan di sini: stackoverflow.com/a/9101056/2063546
Ian
Di OS X El Capitan 10.11.6, ini tidak berfungsi, tetapi jawaban resmi stackoverflow.com/a/1068700/9636 berfungsi dengan baik.
Heath Borders
42

Tidak awk, tapi lebih sederhana:

tail -c +4 UTF8 > UTF8.nobom

Untuk memeriksa BOM:

hd -n 3 UTF8

Jika BOM hadir, Anda akan melihat: 00000000 ef bb bf ...

Steve Clay
sumber
6
BOM adalah 2 byte untuk UTF-16 dan 4 byte untuk UTF-32, dan tentu saja tidak memiliki bisnis di UTF-8.
tchrist
2
@Karolyorv Ya, tepatnya. Penggunaannya tidak disarankan. Itu merusak barang-barang. Pengkodean harus ditentukan oleh protokol tingkat yang lebih tinggi.
tchrist
1
@ tchrist: maksudmu itu merusak barang yang rusak? :) aplikasi yang tepat harus dapat menangani BOM itu.
Karoly Horvath
7
@Karolyorv Maksud saya itu merusak banyak program . Bukankah itu yang saya katakan? Saat Anda membuka streaming dalam encoding UTF-16 atau UTF-32, dekoder mengetahui untuk tidak menghitung BOM. Saat Anda menggunakan UTF-8, decoder menampilkan BOM sebagai data. Ini adalah kesalahan sintaks dalam program yang tak terhitung banyaknya. Bahkan decoder Java berperilaku seperti ini, DENGAN DESAIN! BOM pada file UTF-8 salah tempat dan merepotkan: itu adalah kesalahan! Mereka merusak banyak hal. Bahkan hanya cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8akan rusak. Jangan pernah menggunakan BOM pada UTF-8. Titik.
tchrist
6
hdtidak tersedia pada OS X (per 10.8.2), sehingga untuk memeriksa untuk UTF-8 BOM sana Anda dapat menggunakan berikut: head -c 3 file | od -t x1.
mklement0
21

Selain mengubah ujung baris CRLF ke LF, dos2unixjuga menghapus BOM:

dos2unix *.txt

dos2unix juga mengonversi file UTF-16 dengan BOM (tetapi bukan file UTF-16 tanpa BOM) menjadi UTF-8 tanpa BOM:

$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16be>bom-utf16be
$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16le>bom-utf16le
$ printf '\ufeffä\n'>bom-utf8
$ printf 'ä\n'|iconv -f utf-8 -t utf-16be>utf16be
$ printf 'ä\n'|iconv -f utf-8 -t utf-16le>utf16le
$ printf 'ä\n'>utf8
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be feff00e4000a
bom-utf16le fffee4000a00
   bom-utf8 efbbbfc3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a
$ dos2unix -q *
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be c3a40a
bom-utf16le c3a40a
   bom-utf8 c3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a
Lri
sumber
3

Saya tahu pertanyaan itu ditujukan pada unix / linux, saya pikir akan bermanfaat untuk menyebutkan opsi yang bagus untuk unix-challenge (di windows, dengan UI).
Saya mengalami masalah yang sama pada proyek WordPress (BOM menyebabkan masalah dengan rss feed dan validasi halaman) dan saya harus melihat semua file di pohon direktori yang cukup besar untuk menemukan file yang ada di BOM. Menemukan aplikasi bernama Replace Pioneer dan di dalamnya:

Batch Runner -> Search (untuk menemukan semua file di subfolder) -> Replace Template -> Binary remove BOM (ada pencarian yang sudah jadi dan ganti template untuk ini).

Itu bukan solusi yang paling elegan dan memang membutuhkan penginstalan program, yang merupakan sisi negatifnya. Tapi begitu saya menemukan apa yang terjadi di sekitar saya, itu bekerja seperti pesona (dan menemukan 3 file dari sekitar 2300 yang ada dengan BOM).

Arnon Zamir
sumber
1
Saya sangat senang ketika saya menemukan solusi Anda, namun saya tidak memiliki hak istimewa untuk menginstal perangkat lunak di komputer perusahaan. Butuh banyak waktu hari ini, sampai saya menemukan alternatifnya: Menggunakan Notepad ++ dengan plugin PythonScript. superuser.com/questions/418515/… Terima kasih!
Hoàng Long