Использование awk для удаления метки порядка байтов

Как будет выглядеть awk скрипт (предположительно однострочный) для удаления спецификации?

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

  • печатать каждую строку после первой (NR > 1)
  • для первой строки: если она начинается с #FE #FF или #FF #FE, удалите их и распечатайте остальные

person Boldewyn    schedule 01.07.2009    source источник


Ответы (5)


Попробуй это:

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

В первой записи (строке) удалите символы спецификации. Распечатайте каждую запись.

Или немного короче, зная, что по умолчанию в awk выполняется печать записи:

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

1 - кратчайшее условие, которое всегда оценивается как истинное, поэтому печатается каждая запись.

Наслаждаться!

- ДОБАВЛЕНИЕ -

FAQ по метке порядка байтов Unicode включает следующую таблицу, в которой перечислены точные байты спецификации для каждого кодировка:

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 байтам спецификации из приведенной выше таблицы.

person Bartosz    schedule 01.07.2009
comment
Кажется, что точка в середине подвыражения - это слишком много (по крайней мере, моя awk на это жалуется). Кроме того, это именно то, что я искал, спасибо! - person Boldewyn; 01.07.2009
comment
Однако это решение работает только для файлов в кодировке UTF-8. Для других, таких как UTF-16, см. Соответствующее представление спецификации в Википедии: en.wikipedia.org/wiki/ Byte_order_mark - person Boldewyn; 01.07.2009
comment
Я согласен с предыдущим комментарием; точка не находится в середине этого оператора и делает этот замечательный небольшой фрагмент примером синтаксической ошибки awk. - person Brandon Rhodes; 08.12.2009
comment
Итак: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILE и убедитесь, что INFILE и OUTFILE разные! - person Steve Clay; 12.02.2010
comment
Если вы использовали perl -i.orig -pe 's/^\x{FFFE}//' badfile, вы могли бы полагаться на свои переменные PERL_UNICODE и / или PERLIO для кодирования. PERL_UNICODE = SD будет работать с UTF-8; для остальных вам понадобится PERLIO. - person tchrist; 15.08.2011
comment
Может быть, немного более короткая версия: awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1' - person TrueY; 06.06.2013
comment
Отлично работает на OS X El Capitan 10.11.6. - person Heath Borders; 13.09.2016
comment
/! \ Обе команды стерли мой файл, как побочный эффект изменения кодировки ... Очень повезло, что сначала они сделали резервную копию. - person OroshiX; 20.07.2018
comment
Если вы пытаетесь просто изменить файл (не создавать новый) и по какой-то причине не можете использовать sed (согласно ответу ниже), обязательно используйте -i inplace и не помещайте входной файл в качестве выходного файла, который сотрет файл! - person Blayzeing; 26.11.2020

Используя 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 не упоминается поддержка шестнадцатеричного экранирования ala \xef.

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

awk '…' INFILE | sponge INFILE
person Denilson Sá Maia    schedule 01.09.2010
comment
Я попробовал вторую команду именно на Mac OS X, и результат был успешным, но на самом деле подстановки не произошло. - person Trejkaz; 06.12.2012
comment
Стоит отметить, что эти команды заменяют одну конкретную последовательность байтов, которая является одной из возможных байтовых последовательностей. марки. Возможно, у вашего файла была другая последовательность спецификации. (Я ничем не могу помочь, потому что у меня нет Mac) - person Denilson Sá Maia; 07.12.2012
comment
Когда я попробовал вторую команду в OS X для файла, который использовал 0xef 0xbb 0xbf в качестве спецификации, на самом деле замена не производилась. - person John Wiseman; 13.10.2015
comment
В OSX я мог заставить это работать только через Perl, как показано здесь: stackoverflow.com/a/9101056/2063546 - person Ian; 19.08.2016
comment
В OS X El Capitan 10.11.6 это не работает, но официальный ответ stackoverflow.com/a/1068700/9636 работает отлично. - person Heath Borders; 13.09.2016

Не на awk, а попроще:

tail -c +4 UTF8 > UTF8.nobom

Чтобы проверить спецификацию:

hd -n 3 UTF8

Если есть спецификация, вы увидите: 00000000 ef bb bf ...

person Steve Clay    schedule 15.02.2010
comment
Спецификации - это 2 байта для UTF-16 и 4 байта для UTF-32, и, конечно, не имеют никакого отношения к UTF-8. - person tchrist; 15.08.2011
comment
@tchrist: из википедии: Стандарт Unicode разрешает спецификацию в UTF-8, но не требует и не рекомендует ее использование. Порядок байтов не имеет значения в UTF-8, поэтому в UTF-8 спецификация служит только для идентификации текстового потока или файла как UTF-8. - person Karoly Horvath; 17.03.2012
comment
@KarolyHorvath Да, именно так. Его использование не рекомендуется. Это ломает вещи. Кодировка должна определяться протоколом более высокого уровня. - person tchrist; 17.03.2012
comment
@tchrist: ты имеешь в виду, что он ломает сломанные вещи? :) правильные приложения должны уметь обрабатывать эту спецификацию. - person Karoly Horvath; 17.03.2012
comment
@KarolyHorvath Я имею в виду, что он ломает множество программ. Разве я не так сказал? Когда вы открываете поток в кодировках UTF-16 или UTF-32, декодер не учитывает спецификацию. Когда вы используете UTF-8, декодеры представляют спецификацию как данные. Это синтаксическая ошибка в бесчисленных программах. Даже декодер Java ведет себя таким образом, ПО ДИЗАЙНУ! спецификации для файлов UTF-8 неуместны и неудобны: это ошибка! Они ломают многие вещи. Даже просто cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8 будет сломан. Никогда не используйте спецификацию в UTF-8. Период. - person tchrist; 17.03.2012
comment
@@ tchrist :: это то, что вы сказали ... а я сказал кое-что еще. Кстати, декодер Java не нарушен дизайном. это ошибка, и они оставили ее для обратной совместимости. - person Karoly Horvath; 17.03.2012
comment
hd недоступен в OS X (начиная с 10.8.2), поэтому для проверки спецификации UTF-8 вы можете использовать следующее: head -c 3 file | od -t x1. - person mklement0; 13.10.2012
comment
if [[ "file a.txt | grep -o 'с BOM'" == "BOM" ]]; также можно использовать - person Benoit Duffez; 11.10.2014
comment
hexdump и xdd должны работать вместо hd, если это недоступно в вашей системе. - person Seldom 'Where's Monica' Needy; 15.05.2016

Помимо преобразования окончаний строк CRLF в LF, dos2unix также удаляет спецификации:

dos2unix *.txt

dos2unix также преобразует файлы UTF-16 с спецификацией (но не файлы UTF-16 без спецификации) в UTF-8 без спецификации:

$ 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
person Lri    schedule 29.09.2013

Я знаю, что вопрос был направлен на unix / linux, подумал, что стоит упомянуть хороший вариант для unix-проблемных (в Windows, с пользовательским интерфейсом).
Я столкнулся с той же проблемой в проекте WordPress (спецификация вызывала проблемы с RSS-потоком и проверкой страницы), и мне пришлось просмотреть все файлы в довольно большом дереве каталогов, чтобы найти тот, который был с спецификацией. Нашел приложение под названием Replace Pioneer и в нем:

Batch Runner -> Search (чтобы найти все файлы в подпапках) -> Replace Template -> Binary remove BOM (для этого есть готовый шаблон поиска и замены).

Это было не самое элегантное решение и требовало установки программы, что является недостатком. Но как только я узнал, что происходит вокруг меня, это сработало как шарм (и нашел 3 файла из примерно 2300, которые были с спецификацией).

person Arnon Zamir    schedule 21.03.2012
comment
Я так счастлив, когда нашел ваше решение, однако у меня нет привилегии устанавливать программное обеспечение на компьютер компании. Сегодня потребовалось много времени, пока я не придумал альтернативу: использование Notepad ++ с плагином PythonScript. superuser.com/questions/418515/ В любом случае спасибо! - person Hoàng Long; 13.05.2015