Використовуючи awk для видалення позначки порядку байт


105

Як би awk виглядав сценарій (імовірно, однолінійний) для видалення BOM ?

Специфікація:

  • надрукувати кожен рядок після першого (NR > 1 )
  • для першого рядка: якщо він починається з #FE #FFабо #FF #FE, видаліть їх та надрукуйте решту

Відповіді:


114

Спробуйте це:

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 (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, дивіться у Вікіпедії відповідне представлення BOM: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn

2
Отже: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILEі переконайтеся, що INFILE та OUTFILE різні!
Стів Клей

1
Якщо ви використовували, perl -i.orig -pe 's/^\x{FFFE}//' badfileви можете розраховувати на свої PERL_UNICODE та / або PERLIO envariables для кодування. 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не йдеться про підтримку шістнадцяткової втечі ала \xef.

Подібного трюку можна досягти з будь-якою програмою, перейшовши на spongeінструмент від moreutils :

awk '…' INFILE | sponge INFILE

5
Я спробував другу команду саме на Mac OS X, і результат був "успіх", але заміни насправді не відбулося.
Трежказ

1
Варто відзначити, що ці команди замінюють одну конкретну послідовність байтів, яка є однією з можливих байт-порядкових позначок . Можливо, у вашому файлі була інша послідовність BOM. (Я не можу допомогти іншим, окрім цього, оскільки у мене немає Mac)
Denilson Sá Maia

3
Коли я спробував другу команду в OS X у файлі, який використовував 0xef 0xbb 0xbf як BOM, він фактично не робив заміни.
Джон Вісман

В OSX я міг змусити це працювати лише через perl, як показано тут: stackoverflow.com/a/9101056/2063546
Ian

У OS X El Capitan 10.11.6це не працює, але офіційна відповідь stackoverflow.com/a/1068700/9636 працює чудово.
Гейт Межі

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.
Каролі Хорват

7
@KarolyHorvath Я маю на увазі, що він порушує багато програм . Хіба це не те, що я сказав? Коли ви відкриваєте потік у кодуванні UTF-16 або UTF-32, декодер знає, що не рахувати BOM. Під час використання UTF-8 декодери представляють BOM як дані. Це синтаксична помилка в незліченних програмах. Навіть декодер Java поводиться так, ЗА КОРОБКОЮ! 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, з інтерфейсом користувача).
Я зіткнувся з тією ж проблемою в проекті WordPress (BOM викликав проблеми з RSS-стрічкою та валідацією сторінок), і мені довелося вивчити всі файли у досить великому дереві каталогів, щоб знайти той, який був у BOM. Знайдено додаток під назвою Замінити піонер і в ньому:

Batch Runner -> Пошук (щоб знайти всі файли у підпапках) -> Замінити шаблон -> Бінарне видалення BOM (для цього є готовий шаблон пошуку та заміни).

Це не було найелегантнішим рішенням, і для цього потрібна була встановити програму, що є і недоліком. Але як тільки я дізнався, що відбувається навколо мене, це спрацювало як шарм (і знайшов 3 файли з приблизно 2300, які були з BOM).


1
Я такий щасливий, коли знайшов ваше рішення, проте не маю привілею встановлювати програмне забезпечення на комп'ютер компанії. Сьогодні пройшло багато часу, поки я не з'ясував альтернативу: Використання Notepad ++ із плагіном PythonScript. superuser.com/questions/418515/… Дякую все одно!
Хоанг Лонг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.