ใช้ awk เพื่อลบเครื่องหมายลำดับไบต์


105

วิธีจะawkสคริปต์ (สันนิษฐานหนึ่งซับ) ถอดBOMมีลักษณะเหมือน?

ข้อมูลจำเพาะ:

  • พิมพ์ทุกบรรทัดหลังจากแรก ( NR > 1)
  • สำหรับบรรทัดแรก: หากขึ้นต้นด้วย#FE #FFหรือ#FF #FEให้ลบออกและพิมพ์ส่วนที่เหลือ

คำตอบ:


115

ลองสิ่งนี้:

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

ในระเบียนแรก (บรรทัด) ให้ลบอักขระ BOM พิมพ์ทุกบันทึก

หรือสั้นกว่าเล็กน้อยโดยใช้ความรู้ว่าการดำเนินการเริ่มต้นใน awk คือการพิมพ์บันทึก:

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

1 เป็นเงื่อนไขที่สั้นที่สุดที่ประเมินเป็นจริงเสมอดังนั้นแต่ละเร็กคอร์ดจึงถูกพิมพ์ออกมา

สนุก!

- เพิ่มเติม -

คำถามที่พบบ่อย Unicode Byte Order Mark (BOM)ประกอบด้วยตารางต่อไปนี้ที่แสดงรายการ BOM ไบต์ที่แน่นอนสำหรับการเข้ารหัสแต่ละรายการ:

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

ดังนั้นคุณสามารถดูว่า\xef\xbb\xbfสอดคล้องกับEF BB BF UTF-8ไบต์ BOM จากตารางด้านบนอย่างไร


1
ดูเหมือนว่าจุดที่อยู่ตรงกลางของคำสั่งย่อยจะมากเกินไป (อย่างน้อย awk ของฉันก็บ่นเกี่ยวกับเรื่องนี้) นอกจากนี้ยังเป็นสิ่งที่ฉันค้นหาขอบคุณ!
Boldewyn

5
การแก้ปัญหานี้ แต่ทำงานเพียงสำหรับ UTF-8 ไฟล์ที่เข้ารหัส สำหรับคนอื่น ๆ เช่น UTF-16 โปรดดู Wikipedia สำหรับการเป็นตัวแทน BOM ที่เกี่ยวข้อง: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn

2
ดังนั้น: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILEและตรวจสอบให้แน่ใจว่า INFILE และ OUTFILE แตกต่างกัน!
Steve Clay

1
หากคุณใช้perl -i.orig -pe 's/^\x{FFFE}//' badfileคุณสามารถพึ่งพา PERL_UNICODE และ / หรือ PERLIO ของคุณสำหรับการเข้ารหัส PERL_UNICODE = SD ใช้ได้กับ UTF-8; สำหรับคนอื่น ๆ คุณต้องมี PERLIO
tchrist

1
อาจจะสั้นกว่าเล็กน้อย:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY

122

การใช้ GNU sed(บน Linux หรือ Cygwin):

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

บน FreeBSD:

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

ข้อได้เปรียบของการใช้ GNU หรือ FreeBSD sed: -iพารามิเตอร์หมายถึง "ในตำแหน่ง" และจะอัปเดตไฟล์โดยไม่จำเป็นต้องเปลี่ยนเส้นทางหรือเทคนิคแปลก ๆ

บน Mac:

awkวิธีนี้ในคำตอบอื่นใช้งานได้ แต่sedคำสั่งด้านบนไม่ทำงาน อย่างน้อยในเอกสารของ Mac (Sierra) sedไม่ได้กล่าวถึงการรองรับการหลบหนีเลขฐานสิบหก\xefAla

เคล็ดลับที่คล้ายกันนี้สามารถทำได้กับโปรแกรมใด ๆ โดยไปที่spongeเครื่องมือจากmoreutils :

awk '…' INFILE | sponge INFILE

5
ฉันลองใช้คำสั่งที่สองอย่างแม่นยำบน Mac OS X และผลลัพธ์คือ "สำเร็จ" แต่การทดแทนไม่ได้เกิดขึ้นจริง
Trejkaz

1
เป็นมูลค่า noting คำสั่งเหล่านี้เปลี่ยนลำดับไบต์หนึ่งที่เฉพาะเจาะจงซึ่งเป็นหนึ่งในผู้ที่เป็นไปได้สั่งไบต์เครื่องหมาย บางทีไฟล์ของคุณอาจมีลำดับ BOM ที่แตกต่างกัน (ฉันไม่สามารถช่วยได้นอกจากนั้นเนื่องจากฉันไม่มี Mac)
Denilson Sá Maia

3
เมื่อฉันลองใช้คำสั่งที่สองบน OS X บนไฟล์ที่ใช้ 0xef 0xbb 0xbf เป็น BOM มันไม่ได้ทำการแทนที่จริงๆ
John Wiseman

ใน OSX ฉันสามารถทำให้สิ่งนี้ทำงานได้ผ่าน perl เท่านั้นดังที่แสดงไว้ที่นี่: stackoverflow.com/a/9101056/2063546
Ian

บน OS X El Capitan 10.11.6ไม่ได้ผล แต่คำตอบอย่างเป็นทางการstackoverflow.com/a/1068700/9636 ใช้งานได้ดี
Heath Borders

42

ไม่แย่ แต่ง่ายกว่า:

tail -c +4 UTF8 > UTF8.nobom

ในการตรวจสอบ BOM:

hd -n 3 UTF8

หากมี BOM คุณจะเห็น: 00000000 ef bb bf ...


6
BOM คือ 2 ไบต์สำหรับ UTF-16 และ 4 ไบต์สำหรับ UTF-32 และแน่นอนว่าไม่มีธุรกิจใดอยู่ใน UTF-8 ตั้งแต่แรก
tchrist

2
@KarolyHorvath ใช่เป๊ะ ๆ ไม่แนะนำให้ใช้ มันทำลายสิ่งของ การเข้ารหัสควรระบุโดยโปรโตคอลระดับสูงกว่า
tchrist

1
@tchrist: คุณหมายถึงมันทำให้ของพังเหรอ? :) แอพที่เหมาะสมควรจะจัดการ BOM นั้นได้
Karoly Horvath

7
@KarolyHorvath ฉันหมายความว่ามันแบ่งจำนวนมากของโปรแกรม นั่นคือสิ่งที่ฉันพูดไม่ใช่เหรอ? เมื่อคุณเปิดสตรีมในการเข้ารหัส UTF-16 หรือ UTF-32 ตัวถอดรหัสจะรู้ว่าไม่นับ BOM เมื่อคุณใช้ UTF-8 ตัวถอดรหัสจะแสดง BOM เป็นข้อมูล นี่เป็นข้อผิดพลาดทางไวยากรณ์ในโปรแกรมนับไม่ถ้วน แม้แต่ตัวถอดรหัสของ Java ก็ทำงานในลักษณะนี้ BY DESIGN! BOM ในไฟล์ UTF-8 ถูกใส่ผิดตำแหน่งและมีอาการปวดก้น: เป็นข้อผิดพลาด! พวกเขาทำลายหลายสิ่ง แม้เพียงcat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8จะหัก ห้ามใช้ BOM บน UTF-8 ระยะเวลา
tchrist

6
hdไม่สามารถใช้งานบน OS X ( ณ วันที่ 10.8.2) ดังนั้นในการตรวจสอบ UTF-8 BOM head -c 3 file | od -t x1มีคุณสามารถใช้ต่อไปนี้:
mklement0

21

นอกจากการแปลงส่วนท้ายบรรทัด CRLF เป็น LF แล้วdos2unixยังลบ BOM ด้วย:

dos2unix *.txt

dos2unix ยังแปลงไฟล์ UTF-16 ด้วย BOM (แต่ไม่ใช่ไฟล์ UTF-16 ที่ไม่มี BOM) เป็น UTF-8 โดยไม่มี 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

3

ฉันรู้ว่าคำถามถูกส่งไปที่ unix / linux คิดว่ามันคุ้มค่าที่จะพูดถึงตัวเลือกที่ดีสำหรับ unix ที่ท้าทาย (บน windows พร้อม UI)
ฉันพบปัญหาเดียวกันในโครงการ WordPress (BOM ทำให้เกิดปัญหากับฟีด rss และการตรวจสอบความถูกต้องของเพจ) และฉันต้องตรวจสอบไฟล์ทั้งหมดในแผนผังไดเรกทอรีที่ค่อนข้างใหญ่เพื่อค้นหาไฟล์ที่อยู่กับ BOM พบแอปพลิเคชันชื่อReplace Pioneerและอยู่ในนั้น:

Batch Runner -> Search (เพื่อค้นหาไฟล์ทั้งหมดในโฟลเดอร์ย่อย) -> Replace Template -> Binary ลบ BOM (มีการค้นหาสำเร็จรูปและแทนที่เทมเพลตสำหรับสิ่งนี้)

มันไม่ใช่วิธีแก้ปัญหาที่หรูหราที่สุดและต้องติดตั้งโปรแกรมซึ่งเป็นข้อเสีย แต่เมื่อฉันพบว่าเกิดอะไรขึ้นรอบตัวฉันมันใช้งานได้อย่างมีเสน่ห์ (และพบ 3 ไฟล์จากประมาณ 2300 ที่อยู่กับ BOM)


1
ฉันมีความสุขมากเมื่อพบโซลูชันของคุณ แต่ฉันไม่มีสิทธิ์ติดตั้งซอฟต์แวร์บนคอมพิวเตอร์ของ บริษัท ใช้เวลามากในวันนี้จนกว่าฉันจะหาทางเลือกอื่นได้: การใช้ Notepad ++ กับปลั๊กอิน PythonScript superuser.com/questions/418515/…ขอบคุณต่อไป!
Hoàng Long
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.