tr抱怨“非法字节序列”


24

我是UNIX的新手,我正在使用Kirk McElhearn的“ Mac OS X命令行”自学一些命令。

我试图使用trgrep以便可以在常规的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并且可以正确搜索。


我看不到为什么tr会抱怨,您输入的内容与问题中输入的相同吗?grep找不到您想要的东西,xdoc是定义不正确的标准。没有人真正知道这些文件中的内容,人们对其进行了反向工程,显然该标准没有帮助。
ctrl-alt-delor 2014年

Answers:


29

grep是文本处理工具。它期望它们的输入是文本文件。似乎tr在macOS上也是如此(即使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 X之前的Mac OS中的换行符。自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

由于docx格式的XML文件主要由一行大行组成,因此结果将不太可读。如果要在文档的主体文本中进行搜索,请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,可以在Debian Gnu + Linux上的软件包中使用xml_ppxml-twig-tools(不知道Mac)。
ctrl-alt-delor 2014年

2
Excel for Mac 2011保存带有\ r行尾的CSV文件,因此该tr调用实际上非常相关且有用。
Noah Yetter,2015年

1
与Outlook for Mac 2011一样,当您导出制表符分隔的联系人列表时。
伊万X

1
好吧,我没有足够的声誉来否决这个问题,但是这个答案完全是错误的。它以“ tr期望他们的输入为文本文件” 开头。而POSIX规范明确指出“标准输入可以是任何类型的文件。” 。请更正您的答案。
7heo.tk

@ 7heo.tk“这个答案是不正确完全”是一个总exageration,但你是对的,tr应该处理二进制输入(特别,它应该处理空正确字节)。POSIX并没有明确说明应该如何处理非字符序列的输入。(如果我是一个实现者,我将通过未经修改的无效字节序列(或使用删除它们-s),并向标准委员会提出缺陷。)显然,macOS的tr抱怨它们。
吉尔(Gilles)'所以

13

我想您的语言环境中的charmap是UTF-8,因此您在二进制文件上会遇到问题。只需切换到C语言环境:

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

您可以使用方括号避免两次指定语言。LC_ALL=C ( tr '\r' '\n' < target-file | grep search-string )。但是docx不是C本地的。Is是utf16且压缩且复杂,有人猜测。我希望使用的工具可以将其转换为可以处理的其他格式,例如html或odt(odt也压缩,但定义明确且易于解释)。
ctrl-alt-delor 2014年

1
带有括号(括号)的语法不适用于所有外壳程序(不是bash,不是zsh,不是破折号)。然后,关于MS Word文件,这取决于。我有一些此类文件,其中strings命令提供了明文。
vinc17 2014年

或者,( export LC_ALL=C; tr '\r' '\n' < target-file | grep search-string; )应该工作。
vinc17 2014年

1
strings具有超强能力:它可以读取不只是utf-8或ascii文本的文件。
ctrl-alt-delor 2014年

很抱歉,()我认为那行得通,感谢@ vinc17修复。
ctrl-alt-delor 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.