tr жалуется на «недопустимую последовательность байтов»

24

Я новичок в UNIX и использую «Командную строку Mac OS X» Кирка МакЭлхарна, чтобы научить себя некоторым командам.

Я пытаюсь использовать trи grepтак, чтобы я мог искать текстовые строки в обычном документе MS-Office Word.

$ tr '\r' '\n' < target-file | grep search-string

Но все, что он возвращает, это:

Illegal byte sequence.

robomechanoid:Position-Paper-Final-Draft robertjralph$ tr '\r' '\n' < Position-Paper-Final-Version.docx | grep DeCSS
tr: Illegal byte sequence
robomechanoid:Position-Paper-Final-Draft robertjralph$ 

Я фактически запустил ту же строку в сценарии, в котором я создал, viи он выполняет поиск правильно.

user74886
источник
Я не понимаю, почему tr жаловался, вы печатали так же, как и в вопросе? grep не найдет то, что вы хотите, xdoc - плохо определенный стандарт. Никто действительно не знает, что находится на этих файлах, люди перепроектировали это, очевидно, стандарт не помог.
Ctrl-Alt-Delor

Ответы:

29

grepинструмент для обработки текста Ожидается, что их входные данные будут текстовыми файлами . Похоже, то же самое относится и к trmacOS (хотя trпредполагается, что он поддерживает двоичные файлы).

Компьютеры хранят данные в виде последовательности байтов . Текст - это последовательность символов. Существует несколько способов кодирования символов в виде байтов, называемых кодировками символов . Стандартной кодировкой символов де-факто в большинстве стран мира, особенно в OSX, является UTF-8 , которая является кодировкой для набора символов Unicode . Есть только 256 возможных байтов, но более миллиона возможных символов Unicode, поэтому большинство символов кодируются как несколько байтов. UTF-8 - кодировка переменной длины: в зависимости от символа для кодирования символа может потребоваться от одного до четырех байтов. Некоторые последовательности байтов не представляют какой-либо символ в UTF-8. Следовательно, существуют последовательности байтов, которые не являются допустимыми текстовыми файлами UTF-8.

trжалуется, потому что столкнулся с такой последовательностью байтов. Он ожидает увидеть текстовый файл, закодированный в UTF-8, но он видит двоичные данные, которые не являются допустимыми UTF-8.

Документ Microsoft Word - это не текстовый файл: это текстовый документ. Форматы документов для обработки текстов кодируют не только текст, но и форматирование, встроенные изображения и т. Д. Формат Word, как и большинство форматов обработки текстов, не является текстовым файлом.

Вы можете указать инструментам обработки текста работать с байтами, изменив локаль . В частности, выберите «C» локаль, что в основном означает «ничего особенного». В командной строке вы можете выбрать региональные настройки с переменными среды .

export LC_CTYPE=C
tr '\r' '\n' < target-file | grep search-string

Это не выдаст никакой ошибки, но также не принесет ничего полезного, поскольку target-fileвсе еще является двоичным файлом, который вряд ли будет содержать большинство строк поиска, которые вы укажете.

Кстати, tr '\r' '\n'это не очень полезная команда, если у вас не осталось текстовых файлов из Mac OS 9 или более ранней версии. \r(возврат каретки) был разделителем новой строки в Mac OS до Mac OS X. Начиная с OSX, разделителем новой строки является \n(перевод строки, стандарт Unix), и текстовые файлы не содержат возврат каретки. Windows использует двухсимвольную последовательность CR-LF для представления разрывов строк; tr -d '\r'конвертирует текстовый файл Windows в текстовый файл Unix / Linux / OSX.

Итак, как вы можете искать в документе Word из командной строки? Документ .docxWord на самом деле представляет собой zip-архив, содержащий несколько файлов, основные из которых находятся в формате XML .

unzip -l Position-Paper-Final-Version.docx

Mac OS X включает утилиту zipgrep для поиска внутри zip-файлов.

zipgrep DeCSS Position-Paper-Final-Version.docx

Результат не будет очень читабельным, потому что XML-файлы в формате docx в основном состоят из одной огромной строки. Если вы хотите выполнить поиск внутри основного текста документа, извлеките файл word/document.xmlиз архива. Обратите внимание, что в дополнение к тексту документа этот файл содержит разметку XML, которая представляет структуру документа. Вы можете немного помассировать XML-разметку, sedразбив ее на управляемые строки.

unzip -p Position-Paper-Final-Version.docx word/document.xml |
sed -e 's/></>\n</g' |
grep DeCSS
Жиль "ТАК - перестань быть злым"
источник
1
+1 за хорошее резюме и дополнительные биты. У меня есть одна вещь, чтобы сказать все же. Для форматирования XML вы можете использовать xml_ppего в пакете xml-twig-toolsна Debian Gnu + Linux (не знаю Mac).
Ctrl-Alt-Delor
2
Excel для Mac 2011 сохраняет файлы CSV с окончанием строки \ r, поэтому этот вызов tr на самом деле весьма актуален и полезен.
Ноа Йеттер
1
Как и Outlook for Mac 2011 при экспорте списка контактов с разделителями табуляции.
Иван Икс
1
Ну, у меня недостаточно репутации, чтобы понизить это, но этот ответ совершенно неверен. Он начинается с " tr[...] ожидайте, что их вводом будут текстовые файлы."; в то время как спецификация POSIX четко гласит: «Стандартный ввод может быть любым типом файла». , Пожалуйста, исправьте свой ответ.
7heo.tk
@ 7heo.tk «этот ответ совершенно неправильно» является грубым преувеличением можно , но вы правы, trэто должен обрабатывать двоичный вход (в частности, он должен процесс с нулевым байтом правильно). Тем не менее, в POSIX четко не указано, как он должен обрабатывать ввод, который не является последовательностью символов. (Если бы я был разработчиком, я пропустил бы недопустимые байтовые последовательности через неизмененные (или удалил их -s) и поднял бы дефект в стандартном комитете.) Очевидно, trOS жалуется на них.
Жиль "ТАК - перестать быть злым"
13

Я предполагаю, что ваш charmap из локалей - UTF-8, так что у вас будут проблемы с двоичными файлами. Просто переключитесь на локаль C:

LC_ALL=C tr '\r' '\n' < target-file | LC_ALL=C grep search-string
vinc17
источник
Вы можете использовать скобки, чтобы избежать указания языка дважды. LC_ALL=C ( tr '\r' '\n' < target-file | grep search-string ), Однако docx не является локальным. Это UTF16 и молнии и сложный и кто-нибудь догадаться. Я бы посмотрел, как использовать инструмент, который может конвертировать его в другой формат, который вы можете обрабатывать, например, html или odt (odt также заархивирован, но хорошо определен и легко интерпретируется).
Ctrl-Alt-Delor
1
Синтаксис с квадратными скобками (круглые скобки) не работает со всеми оболочками (не bash, не zsh, не dash). Затем, что касается файла MS Word, это зависит. У меня есть несколько таких файлов, где stringsкоманда дает чистый текст.
vinc17
Как вариант, ( export LC_ALL=C; tr '\r' '\n' < target-file | grep search-string; )должно работать.
vinc17
1
stringsобладает сверхспособностями: он может читать файлы, которые не являются просто текстом UTF-8 или ASCII.
Ctrl-Alt-Delor
Извините за то, ()что я думал, что это сработает, спасибо @ vinc17 за исправление.
Ctrl-Alt-Delor