Làm cách nào tôi có thể xóa BOM khỏi tệp UTF-8?


64

Tôi có một tệp ở dạng mã hóa UTF-8 với BOM và muốn xóa BOM. Có công cụ dòng lệnh linux nào để loại bỏ BOM khỏi tệp không?

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


1
Tôi đã tạo ra một công cụ cực kỳ đơn giản để làm điều đó cách đây vài tháng: oskog97.com/read/?path=/small-scripts/killbom&referer=/. Có thể đáng để cài đặt một cái gì đó giống như trong / usr / local / bin nếu bạn có nhiều tệp được mã hóa UTF-8 bằng BOM.
Oskar Skog

Câu trả lời:


76

Nếu bạn không chắc liệu tệp có chứa BOM UTF-8 hay không, thì điều này (giả sử việc triển khai GNU sed) sẽ xóa BOM nếu nó tồn tại hoặc không thay đổi nếu không.

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

Bạn cũng có thể ghi đè lên tệp hiện có với -itùy chọn:

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

4
điều này có thể không hoạt động trong miền địa phương utf8, nhưng việc thêm vào ghi đè miền địa phương vào c hoặc posix sẽ luôn hoạt động.
hildred

3
@hildred Tôi đã thử nó với en_US.UTF-8miền địa phương và nó đã hoạt động. Khi nào nó sẽ thất bại?
m13r

2
@ m13r, Nó phụ thuộc vào phiên bản của tùy chọn sed và biên dịch. Trong trường hợp thất bại, một phiên bản sed mới với các lớp ký tự Unicode sẽ mang chuỗi ba byte thành một ký tự không khớp với chuỗi ba ký tự. Tuy nhiên trong trường hợp như vậy, bạn có thể thực hiện một trận đấu nhân vật mười sáu bit. Tuy nhiên đây là một tính năng mới và không phổ biến hiện nay. Nếu bạn muốn kiểm tra tôi khuyên bạn nên biên dịch phiên bản mới nhất.
hildred

4
Để sửa nó hoạt động với một sed kích hoạt unicode, hãy làm LC_ALL = C sed '1s / ^ \ xEF \ xBB \ xBF //'
Joshua

1
@mazunki, 1s/có nghĩa là chỉ tìm kiếm dòng đầu tiên; các dòng khác không bị ảnh hưởng. Các ^phương tiện chỉ phù hợp ở đầu dòng (đầu tiên). \xEF\xBB\xBFlà BOM UTF-8 (chuỗi hex đã thoát). //có nghĩa là thay thế bằng không có gì. Tôi có thể đã thêm vào 1cuối (cho 1s/^xEF\xBB\xBF//1), điều đó có nghĩa là chỉ phù hợp với lần xuất hiện đầu tiên của mẫu trên dòng. Nhưng khi tìm kiếm được gắn kết ^, điều này sẽ không tạo ra bất kỳ sự khác biệt nào. Nếu tệp không có BOM ở đầu dòng đầu tiên, mẫu sẽ không khớp và do đó không có thay đổi nào được thực hiện.
CSM

64

Một BOM không có ý nghĩa trong UTF-8. Chúng thường được thêm vào do nhầm lẫn bởi phần mềm không có thật trên hệ điều hành Microsoft.

dos2unix sẽ loại bỏ nó và cũng sẽ xử lý các đặc điểm riêng khác của các tệp văn bản Windows.

dos2unix test.xml

17
Tôi đồng ý rằng BOM được mã hóa UTF-8 không có ý nghĩa gì, nhưng tin hay không, có rất nhiều người nghĩ rằng đó là một ý tưởng tuyệt vời giúp phân biệt UTF-8 với các mã hóa 8 bit khác. Vì vậy, nó là một vấn đề của hương vị. Windows Notepad thêm BOM vào mục đích.
Johan Myréen

17
Có vấn đề gì nếu nó có ý nghĩa hay không, khi bối cảnh chỉ là một câu hỏi về cách loại bỏ nó? Theo Wikipedia, Notepad yêu cầu BOM nhận ra một tệp là UTF-8 và Google Docs cũng thêm nó trong khi xuất tệp dưới dạng văn bản. Tôi nghi ngờ tất cả họ làm điều đó do nhầm lẫn .
ilkkachu

Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
terdon

1
Có cách nào để không chuyển đổi các kết thúc dòng và chỉ loại bỏ BOM với dos2unix?
m13r

2
@ m13r Sau đó sử dụng tập lệnh sed trong câu trả lời này . Điều đó sẽ chỉ loại bỏ bom (nếu nó tồn tại), không có gì khác sẽ được thay đổi.
Mũi tên

26

Có thể xóa BOM khỏi một tệp bằng taillệnh:

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

2
Tại sao 4? BOM có 3 byte.
deviantfan

10
@deviantfan Đó là lý do tại sao bạn cần bắt đầu ở byte thứ 4 nếu bạn muốn bỏ qua nó.
Stéphane Chazelas

9
tailđang sử dụng lập chỉ mục 1?! WTF!
CodeInChaos

5
@CodesInChaos, tail -c -1hoặc tail -c 1( tailthường được sử dụng cho) là nội dung bắt đầu bằng byte cuối cùng, tail -c +1bắt đầu bằng byte đầu tiên. tail -c 0/ tail -c +0cho điều đó sẽ không trực quan hơn nhiều.
Stéphane Chazelas

2
@deviantfan : (dd bs=1 count=3 of=/dev/null; cat) <input >output. Hoặc với GNU (head -c3 >/dev/null; cat)- ngay cả trong UTF8 hoặc ngôn ngữ không đơn lẻ khác; Đầu GNU không 'char' = byte.
dave_thndry_085

20

Sử dụng VIM

  1. Mở tệp trong VIM:

    vi text.xml
    
  2. Xóa mã hóa BOM:

    :set nobomb
    
  3. Lưu và thoát:

    :wq
    

Thật kỳ lạ với vim 8 trên máy mac, tôi có tệp csv utf-8 được tạo bởi Excel và nó bắt đầu bằng <feff>, nhưng :set nobombkhông sửa đổi hoặc xóa nó.
dlamblin

5

Bạn có thể dùng

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

để loại bỏ dấu thứ tự byte khỏi phần đầu của tệp, nếu nó có bất kỳ, cũng như chuyển đổi bất kỳ dòng mới CR LF nào thành LF. Nó báo LANG=C LC_ALL=Ccho shell mà bạn muốn lệnh chạy trong miền địa phương C mặc định (còn được gọi là miền địa phương POSIX mặc định), trong đó ba byte tạo thành Dấu thứ tự Byte được coi là byte. Các -itùy chọn để sed nghĩa tại chỗ. Nếu bạn sử dụng -i.old, thì sed sẽ lưu tệp gốc dưới dạng filename.oldvà tệp mới (với các sửa đổi, nếu có) như filename.


Cá nhân tôi thích có cái này như ~/bin/fix-ms; ví dụ như

#!/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

để nếu tôi cần áp dụng điều này để nói tất cả các tệp và tiêu đề nguồn C (ví dụ mã cũ của tôi từ thời MS-DOS!), tôi chỉ cần chạy

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

hoặc, nếu tôi chỉ muốn xem một tệp như vậy, mà không sửa đổi nó, tôi có thể chạy

~/bin/ms-fix < filename | less

và không thấy xấu xí <U+FEFF>trong thiết bị đầu cuối UTF-8 của tôi.


Tại sao không đơn giản sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"?
Stéphane Chazelas

@ StéphaneChazelas: Bởi vì tôi muốn tập lệnh thoát ngay lập tức nếu có vấn đề với sự thay thế, điều sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"này không xảy ra; nó trả về một mã thoát, nhưng nó xử lý tất cả các tệp được liệt kê trong danh sách đối số trước khi thoát.
Động vật danh nghĩa

@ StéphaneChazelas: Tất nhiên, --trước khi tên tệp là quan trọng: không có nó, tên tệp bắt đầu bằng dấu gạch ngang có thể được coi là tùy chọn của sed. Tôi chỉnh sửa chúng thành câu trả lời của tôi; cảm ơn bạn đã nhắc nhở!
Động vật danh nghĩa

0

Gần đây tôi đã tìm thấy công cụ dòng lệnh nhỏ này có thêm hoặc xóa BOM trên các tệp được mã hóa UTF-8 tùy ý: UTF BOM Utils ( liên kết mới tại github)

Hạn chế nhỏ, bạn chỉ có thể tải xuống mã nguồn C ++ đơn giản. Bạn phải tạo tệp tạo tệp ( ví dụ với CMake ) và tự biên dịch nó, các tệp nhị phân không được cung cấp trên trang này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.