Sử dụng awk để xóa dấu Byte-order


105

Làm thế nào sẽ là một awkkịch bản (có lẽ là một lớp lót) để loại bỏ một BOM cái nhìn như thế nào?

Sự chỉ rõ:

  • in mọi dòng sau dấu ( NR > 1) đầu tiên
  • cho dòng đầu tiên: Nếu nó bắt đầu bằng #FE #FFhoặc #FF #FE, hãy xóa những cái đó và in phần còn lại

Câu trả lời:


114

Thử cái này:

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

Trên bản ghi đầu tiên (dòng), hãy xóa các ký tự BOM. In mọi bản ghi.

Hoặc ngắn hơn một chút, sử dụng kiến ​​thức rằng hành động mặc định trong awk là in bản ghi:

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

1 là điều kiện ngắn nhất luôn đánh giá là true, vì vậy mỗi bản ghi được in ra.

Thưởng thức!

- BỔ SUNG -

Câu hỏi thường gặp về Dấu đơn hàng Unicode Byte (BOM) bao gồm bảng sau liệt kê các byte BOM chính xác cho mỗi bảng mã:

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

Do đó, bạn có thể thấy cách \xef\xbb\xbftương ứng với các EF BB BF UTF-8byte BOM từ bảng trên.


1
Có vẻ như dấu chấm ở giữa câu lệnh phụ là quá nhiều (ít nhất, awk của tôi phàn nàn về điều đó). Bên cạnh đó, nó chính xác là những gì tôi đã tìm kiếm, cảm ơn!
Boldewyn

5
Tuy nhiên, giải pháp này chỉ hoạt động cho các tệp được mã hóa UTF-8. Đối với những người khác, như UTF-16, hãy xem Wikipedia để biết đại diện BOM tương ứng: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn

2
Vì vậy awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILE, hãy đảm bảo rằng INFILE và OUTFILE khác nhau!
Steve Clay

1
Nếu đã sử dụng, perl -i.orig -pe 's/^\x{FFFE}//' badfilebạn có thể dựa vào các biến PERL_UNICODE và / hoặc PERLIO để mã hóa. PERL_UNICODE = SD sẽ hoạt động cho UTF-8; đối với những người khác, bạn cần PERLIO.
tchrist

1
Có thể phiên bản ngắn hơn một chút:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY

122

Sử dụng GNU sed(trên Linux hoặc Cygwin):

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

Trên FreeBSD:

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

Lợi thế của việc sử dụng GNU hoặc FreeBSD sed: -itham số có nghĩa là "tại chỗ" và sẽ cập nhật tệp mà không cần chuyển hướng hoặc các thủ thuật kỳ lạ.

Trên Mac:

awkGiải pháp này trong một câu trả lời khác hoạt động , nhưng sedlệnh trên không hoạt động. Ít nhất trên Mac (Sierra) sedtài liệu không đề cập đến việc hỗ trợ thoát thập lục phân ala \xef.

Một thủ thuật tương tự có thể đạt được với bất kỳ chương trình nào bằng cách chuyển đến spongecông cụ từ moreutils :

awk '…' INFILE | sponge INFILE

5
Tôi đã thử chính xác lệnh thứ hai trên Mac OS X và kết quả là "thành công", nhưng việc thay thế không thực sự xảy ra.
Trejkaz

1
Điều đáng chú ý là các lệnh này thay thế một chuỗi byte cụ thể, là một trong các dấu thứ tự byte có thể có . Có thể tệp của bạn có một chuỗi BOM khác. (Tôi không thể giúp gì khác hơn là vì tôi không có máy Mac)
Denilson Sá Maia

3
Khi tôi thử lệnh thứ hai trên OS X trên tệp sử dụng 0xef 0xbb 0xbf làm BOM, nó thực sự không thực hiện thay thế.
John Wiseman

Trong OSX, tôi chỉ có thể làm cho điều này hoạt động thông qua perl, như được hiển thị ở đây: stackoverflow.com/a/9101056/2063546
Ian

Trên OS X El Capitan 10.11.6, điều này không hoạt động, nhưng câu trả lời chính thức stackoverflow.com/a/1068700/9636 hoạt động tốt.
Heath Borders

42

Không phải awk, nhưng đơn giản hơn:

tail -c +4 UTF8 > UTF8.nobom

Để kiểm tra BOM:

hd -n 3 UTF8

Nếu BOM có mặt, bạn sẽ thấy: 00000000 ef bb bf ...


6
BOM là 2 byte cho UTF-16 và 4 byte cho UTF-32, và tất nhiên không có doanh nghiệp nào ở UTF-8 ngay từ đầu.
tchrist

2
@KarolyHorvath Đúng, chính xác. Việc sử dụng nó không được khuyến khích. Nó phá vỡ mọi thứ. Mã hóa phải được chỉ định bởi một giao thức cấp cao hơn.
tchrist

1
@tchrist: ý bạn là nó làm hỏng đồ? :) các ứng dụng phù hợp sẽ có thể xử lý BOM đó.
Karoly Horvath

7
@KarolyHorvath Ý tôi là nó phá vỡ rất nhiều chương trình . Đó không phải là những gì tôi đã nói? Khi bạn mở một luồng ở mã hóa UTF-16 hoặc UTF-32, bộ giải mã sẽ không đếm BOM. Khi bạn sử dụng UTF-8, bộ giải mã hiển thị BOM dưới dạng dữ liệu. Đây là một lỗi cú pháp trong vô số chương trình. Ngay cả bộ giải mã của Java cũng hoạt động theo cách này, BẰNG THIẾT KẾ! BOM trên tệp UTF-8 bị đặt sai vị trí và cảm giác đau ở mông: đó là một lỗi! Họ phá vỡ nhiều thứ. Thậm chí chỉ cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8sẽ bị phá vỡ. Không bao giờ sử dụng BOM trên UTF-8. Giai đoạn = Stage.
tchrist

6
hdkhông có sẵn trên OS X (tính 10.8.2), do đó để kiểm tra một UTF-8 BOM đó bạn có thể sử dụng như sau: head -c 3 file | od -t x1.
mklement0

21

Ngoài việc chuyển đổi phần cuối dòng CRLF thành LF, dos2unixcũng loại bỏ các BOM:

dos2unix *.txt

dos2unix cũng chuyển đổi tệp UTF-16 có BOM (nhưng không phải tệp UTF-16 không có BOM) thành UTF-8 không có 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

Tôi biết câu hỏi hướng đến unix / linux, tôi nghĩ sẽ đáng để đề cập đến một lựa chọn tốt cho unix bị thách thức (trên windows, với giao diện người dùng).
Tôi gặp phải vấn đề tương tự trên một dự án WordPress (BOM đã gây ra sự cố với nguồn cấp dữ liệu rss và xác thực trang) và tôi phải xem xét tất cả các tệp trong một cây thư mục khá lớn để tìm tệp có trong BOM. Tìm thấy một ứng dụng tên là Replace Pioneer và trong đó:

Batch Runner -> Search (để tìm tất cả các tệp trong các thư mục con) -> Replace Template -> Binary remove BOM (có một mẫu tìm kiếm và thay thế được tạo sẵn cho việc này).

Nó không phải là giải pháp thanh lịch nhất và nó yêu cầu cài đặt một chương trình, đó là một nhược điểm. Nhưng một khi tôi phát hiện ra những gì đang diễn ra xung quanh mình, nó hoạt động như một cái duyên (và tìm thấy 3 tệp trong số khoảng 2300 tệp có BOM).


1
Tôi rất vui khi tôi tìm thấy giải pháp của bạn, tuy nhiên tôi không có đặc quyền cài đặt phần mềm trên máy tính của công ty. Hôm nay đã mất rất nhiều thời gian cho đến khi tôi tìm ra giải pháp thay thế: Sử dụng Notepad ++ với plugin PythonScript. superuser.com/questions/418515/… Vẫn cảm ơn!
Hoàng Long
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.