ฉันจะลบ BOM ออกจากไฟล์ UTF-8 ได้อย่างไร


63

ฉันมีไฟล์ในการเข้ารหัส UTF-8 ด้วย BOM และต้องการลบ BOM มีเครื่องมือบรรทัดคำสั่ง linux เพื่อลบ BOM จากไฟล์หรือไม่?

$ file test.xml
test.xml:  XML 1.0 document, UTF-8 Unicode (with BOM) text, with very long lines


1
ฉันได้ทำเครื่องมือง่ายๆอย่างง่าย ๆ ที่จะทำเมื่อไม่กี่เดือนที่ผ่านมา: oskog97.com/read/?path=/small-scripts/killbom&referer=/…อาจคุ้มค่าที่จะติดตั้งสิ่งที่ต้องการใน / usr / local / bin ถ้า คุณมีไฟล์ที่เข้ารหัส UTF-8 จำนวนมากที่มี BOM
Oskar Skog

คำตอบ:


76

หากคุณไม่แน่ใจว่าไฟล์นั้นมี UTF-8 BOM หรือไม่หากนี่คือการดำเนินการตาม GNU sed) จะลบ BOM หากมีอยู่หรือไม่ทำการเปลี่ยนแปลงหากไม่มี

sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt

คุณสามารถเขียนทับไฟล์ที่มีอยู่ด้วย-iตัวเลือก:

sed -i '1s/^\xEF\xBB\xBF//' orig.txt

4
สิ่งนี้อาจไม่ทำงานใน locale utf8 แต่การเตรียมการแทนที่ locale ไปยัง c หรือ posix จะเป็นการทำงานเสมอ
hildred

3
@hildred ฉันได้ทำการทดสอบกับen_US.UTF-8สถานที่แล้วและใช้งานได้ มันจะล้มเหลวเมื่อใด
m13r

2
@ m13r ขึ้นอยู่กับเวอร์ชันของตัวเลือก sed และคอมไพล์ ในกรณีที่ล้มเหลวเวอร์ชั่นใหม่ของ sed ที่มีคลาสอักขระ Unicode จะนำลำดับสามไบต์มาเป็นอักขระเดี่ยวซึ่งไม่ตรงกับลำดับอักขระสามตัว อย่างไรก็ตามในกรณีเช่นนี้คุณสามารถจับคู่อักขระได้สิบหกบิต อย่างไรก็ตามนี่เป็นคุณสมบัติใหม่และไม่ได้นำเสนอในระดับสากล หากคุณต้องการทดสอบฉันแนะนำให้รวบรวมเวอร์ชั่นล่าสุด
hildred

4
หากต้องการแก้ไขให้ทำงานกับ sed ที่เปิดใช้งาน unicode ให้ทำ LC_ALL = C sed '1s / ^ \ xEF \ xBB \ xBF //'
Joshua

1
@mazunki 1s/หมายถึงค้นหาเฉพาะบรรทัดแรกเท่านั้น บรรทัดอื่นไม่ได้รับผลกระทบ ^วิธีการเดียวที่ตรงกับจุดเริ่มต้นของ (ตอนแรก) สาย \xEF\xBB\xBFคือ UTF-8 BOM (สตริงเลขฐานสิบหกที่ใช้ Escape) //หมายถึงการแทนที่ด้วยอะไร ฉันสามารถเพิ่ม1ไปยังจุดสิ้นสุด (สำหรับ1s/^xEF\xBB\xBF//1) ซึ่งจะหมายถึงเฉพาะการเกิดขึ้นครั้งแรกของรูปแบบในบรรทัด แต่เมื่อการค้นหาถูกยึดด้วย^สิ่งนี้จะไม่สร้างความแตกต่างเลย หากไฟล์ไม่มี BOM ที่จุดเริ่มต้นของบรรทัดแรกรูปแบบจะไม่ตรงกันและทำให้ไม่มีการเปลี่ยนแปลง
CSM

64

BOM ไม่สมเหตุสมผลใน UTF-8 โดยทั่วไปจะมีการเพิ่มซอฟต์แวร์ผิดพลาดบน Microsoft OSes

dos2unix จะลบมันและดูแลไอดีอื่น ๆ ของไฟล์ข้อความ Windows

dos2unix test.xml

17
ฉันยอมรับว่า BOM ที่เข้ารหัส UTF-8 ไม่สมเหตุสมผล แต่เชื่อหรือไม่มีคนจำนวนมากที่คิดว่าเป็นความคิดที่ดีที่ช่วยแยกความแตกต่าง UTF-8 จากการเข้ารหัส 8 บิตอื่น ๆ ดังนั้นมันจึงเป็นเรื่องของรสนิยม Windows Notepad เพิ่ม BOM ตามวัตถุประสงค์
Johan Myréen

17
มันจะมีความสำคัญอย่างไรถ้ามันสมเหตุสมผลหรือไม่เมื่อบริบทเป็นเพียงคำถามเกี่ยวกับวิธีการเอาออก ตามที่ Wikipedia, Notepad ต้องการให้ BOM รับรู้ไฟล์เป็น UTF-8 และ Google Docs ยังเพิ่มมันในขณะที่ส่งออกไฟล์เป็นข้อความ ฉันสงสัยพวกเขาทุกคนทำมันด้วยความผิดพลาด
ilkkachu

ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
terdon

1
มีวิธีที่จะไม่แปลงจุดสิ้นสุดบรรทัดและเพิ่งลบ BOM ด้วยdos2unixหรือไม่
m13r

2
@ m13r จากนั้นใช้สคริปต์ sed ในคำตอบนี้ ที่จะลบเพียง bom (ถ้ามี) ไม่มีอะไรจะเปลี่ยนแปลง
ลูกศร

25

เป็นไปได้ที่จะลบ BOM ออกจากไฟล์ด้วยtailคำสั่ง:

tail -c +4 withBOM.txt > withoutBOM.txt

2
ทำไมต้อง 4 BOM มี 3 ไบต์
deviantfan

10
@deviantfan ซึ่งเป็นสาเหตุที่คุณต้องเริ่มต้นที่ไบต์ที่ 4 หากคุณต้องการข้ามมัน
Stéphane Chazelas

9
tailกำลังใช้การจัดทำดัชนีตาม 1! WTF!
CodesInChaos

5
@CodesInChaos tail -c -1หรือtail -c 1(สิ่งที่tailใช้โดยทั่วไป) เป็นเนื้อหาที่เริ่มต้นด้วยไบต์สุดท้ายtail -c +1เริ่มต้นด้วยไบต์แรก tail -c 0/ tail -c +0สำหรับสิ่งนั้นจะไม่ได้ใช้งานง่ายขึ้น
Stéphane Chazelas

2
(dd bs=1 count=3 of=/dev/null; cat) <input >output@deviantfan: หรือกับ GNU (head -c3 >/dev/null; cat)- แม้ใน UTF8 หรือโลแคลอื่นที่ไม่ใช่ซิงเกิลไบต์ หัวของ GNU ทำหน้าที่ 'char' = ไบต์
dave_thompson_085

20

ใช้ VIM

  1. เปิดไฟล์ใน VIM:

    vi text.xml
    
  2. ลบการเข้ารหัส BOM:

    :set nobomb
    
  3. บันทึกและออก:

    :wq
    

อย่างแปลกประหลาดกับ vim 8 บน mac ฉันมีไฟล์ csv utf-8 ที่สร้างโดย Excel และเริ่มต้นด้วย<feff>แต่:set nobombก็ไม่ได้แก้ไขหรือลบมัน
dlamblin

5

คุณสามารถใช้ได้

LANG=C LC_ALL=C sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- filename

เพื่อลบเครื่องหมายคำสั่งซื้อไบต์จากจุดเริ่มต้นของไฟล์ถ้ามีรวมถึงแปลงบรรทัดใหม่ CR LF เป็น LF เท่านั้น LANG=C LC_ALL=Cบอกเปลือกคุณต้องการคำสั่งในการทำงานในสถานที่เริ่มต้น C (ยังเป็นที่รู้จักสถาน POSIX เริ่มต้น) ที่สามไบต์รูปมาร์คเพื่อ byte จะถือว่าเป็นไบต์ -iตัวเลือกในการ sed หมายความว่าในสถานที่ ถ้าคุณใช้-i.oldแล้ว sed บันทึกไฟล์ต้นฉบับเป็นfilename.oldและไฟล์ใหม่ filename(มีการปรับเปลี่ยนถ้ามี)


โดยส่วนตัวฉันชอบที่จะมีสิ่งนี้เป็น~/bin/fix-ms; ตัวอย่างเช่น

#!/bin/dash
export LANG=C LC_ALL=C
if [ $# -gt 0 ]; then
    for FILE in "$@" ; do
        sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$FILE" || exit 1
    done
else
    exec sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//'
fi

ดังนั้นถ้าฉันต้องใช้สิ่งนี้เพื่อบอกว่าไฟล์ต้นฉบับและส่วนหัวของ C ทั้งหมด (โค้ดเก่าของฉันจากยุค MS-DOS เช่น!) ฉันแค่เรียกใช้

find . -name '*.[CHch]' -print0 | xargs -r0 ~/bin/ms-fix

หรือถ้าฉันแค่ต้องการดูไฟล์ดังกล่าวโดยไม่แก้ไขมันฉันก็สามารถรันได้

~/bin/ms-fix < filename | less

และไม่เห็นสิ่งที่น่าเกลียด<U+FEFF>ในเทอร์มินัล UTF-8 ของฉัน


ทำไมไม่ง่าย ๆsed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"?
Stéphane Chazelas

@ StéphaneChazelas: เพราะฉันต้องการให้สคริปต์ออกทันทีหากมีปัญหากับการเปลี่ยนซึ่งsed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"ไม่ได้ทำ; มันจะส่งกลับรหัสทางออก แต่จะประมวลผลไฟล์ทั้งหมดที่ระบุไว้ในรายการอาร์กิวเมนต์ก่อนที่จะออก
สัตว์ที่กำหนด

@ StéphaneChazelas: --แน่นอนว่าชื่อไฟล์ก่อนหน้านี้สำคัญ: โดยไม่มีชื่อไฟล์ที่ขึ้นต้นด้วยเส้นประอาจถูกพิจารณาว่าเป็นตัวเลือกโดย sed ฉันแก้ไขสิ่งเหล่านั้นในคำตอบของฉัน; ขอบคุณสำหรับการเตือน!
สัตว์ที่กำหนด

0

เมื่อเร็ว ๆ นี้ฉันพบเครื่องมือบรรทัดคำสั่งเล็ก ๆ นี้ซึ่งเพิ่มหรือลบ BOM ในไฟล์ที่เข้ารหัส UTF-8 arbitary: UTF BOM Utils ( ลิงก์ใหม่ที่ github)

ข้อเสียเปรียบเล็กน้อยคุณสามารถดาวน์โหลดได้เฉพาะซอร์สโค้ด C ++ เท่านั้น คุณต้องสร้าง makefile (ด้วยCMakeเป็นต้น) และคอมไพล์ด้วยตัวเองไบนารีจะไม่มีให้ในหน้านี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.