tr se queja de "secuencia de bytes ilegal"

24

Soy nuevo en UNIX y estoy usando la "Línea de comandos de Mac OS X" de Kirk McElhearn para enseñarme algunos comandos.

Estoy intentando utilizar try greppara poder buscar cadenas de texto en un documento de Word de MS-Office normal.

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

Pero todo lo que devuelve es:

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$ 

Realmente ejecuté la misma línea en un script que creé viy realiza la búsqueda correctamente.

usuario74886
fuente
No puedo ver por qué tr se quejaría, ¿escribiste lo mismo que escribiste en la pregunta? grep no encontrará lo que busca, xdoc es un estándar mal definido. Nadie sabe realmente qué hay en esos archivos, la gente lo ha modificado, aparentemente el estándar no fue de ayuda.
ctrl-alt-delor

Respuestas:

29

grepEs una herramienta de procesamiento de texto. Espera que su entrada sean archivos de texto . Parece que lo mismo ocurre trcon macOS (aunque trse supone que admite archivos binarios).

Las computadoras almacenan datos como secuencias de bytes . Un texto es una secuencia de caracteres. Hay varias formas de codificar caracteres como bytes, llamadas codificaciones de caracteres . La codificación de caracteres estándar de facto en la mayoría del mundo, especialmente en OSX, es UTF-8 , que es una codificación para el conjunto de caracteres Unicode . Hay solo 256 bytes posibles, pero más de un millón de caracteres Unicode posibles, por lo que la mayoría de los caracteres están codificados como bytes múltiples. UTF-8 es una codificación de longitud variable: dependiendo del carácter, puede tomar de uno a cuatro bytes codificar un carácter. Algunas secuencias de bytes no representan ningún carácter en UTF-8. Por lo tanto, hay secuencias de bytes que no son archivos de texto UTF-8 válidos.

trse queja porque encontró una secuencia de bytes de este tipo. Espera ver un archivo de texto codificado en UTF-8, pero ve datos binarios que no son válidos UTF-8.

Un documento de Microsoft Word no es un archivo de texto: es un documento de procesamiento de texto. Los formatos de documentos de procesamiento de texto codifican no solo texto, sino también formato, imágenes incrustadas, etc. El formato de Word, como la mayoría de los formatos de procesamiento de texto, no es un archivo de texto.

Puede indicar a las herramientas de procesamiento de texto que operen en bytes cambiando la configuración regional . Específicamente, seleccione la configuración regional "C", que básicamente significa "nada lujoso". En la línea de comando, puede elegir la configuración regional con variables de entorno .

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

Esto no emitirá ningún error, pero tampoco hará nada útil ya que target-filetodavía es un archivo binario que es poco probable que contenga la mayoría de las cadenas de búsqueda que especificará.

Por cierto, tr '\r' '\n'no es un comando muy útil a menos que le queden archivos de texto de Mac OS 9 o anterior. \r(retorno de carro) era el separador de nueva línea en Mac OS antes de Mac OS X. Desde OSX, el separador de nueva línea es \n(avance de línea, el estándar de Unix) y los archivos de texto no contienen retornos de carro. Windows usa la secuencia de dos caracteres CR-LF para representar saltos de línea; tr -d '\r'convertiría un archivo de texto de Windows en un archivo de texto Unix / Linux / OSX.

Entonces, ¿cómo puede buscar en un documento de Word desde la línea de comandos? Un .docxdocumento de Word es en realidad un archivo zip que contiene varios archivos, los principales están en XML .

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

Mac OS X incluye la utilidad zipgrep para buscar dentro de archivos zip.

zipgrep DeCSS Position-Paper-Final-Version.docx

El resultado no será muy legible porque los archivos XML en formato docx consisten principalmente en una gran línea. Si desea buscar dentro del texto del cuerpo principal del documento, extraiga el archivo word/document.xmldel archivo. Tenga en cuenta que, además del texto del documento, este archivo contiene marcado XML que representa la estructura del documento. Puede masajear un poco el marcado XML sedpara dividirlo en líneas manejables.

unzip -p Position-Paper-Final-Version.docx word/document.xml |
sed -e 's/></>\n</g' |
grep DeCSS
Gilles 'SO- deja de ser malvado'
fuente
1
+1 para un buen resumen y bits extra. Aunque tengo una cosa que decir. Para formatear el xml, puede usarlo xml_ppen el paquete xml-twig-toolsen Debian Gnu + Linux (no conoce un mac).
ctrl-alt-delor
2
Excel para Mac 2011 guarda los archivos CSV con \ r terminaciones de línea, por lo que esta invocación tr es de hecho bastante relevante y útil.
Noah Yetter
1
Al igual que Outlook para Mac 2011 cuando exporta una lista de contactos delimitados por tabuladores.
Ivan X
1
Bueno, no tengo suficiente reputación para desestimar esto, pero esta respuesta es completamente incorrecta. Comienza con " tr[...] espera que su entrada sean archivos de texto"; mientras que la especificación POSIX establece claramente "La entrada estándar puede ser cualquier tipo de archivo". . Por favor corrige tu respuesta.
7heo.tk
@ 7heo.tk "esta respuesta es completamente incorrecta" es una exageración, pero tienes razón, trse supone que procesa la entrada binaria (en particular, se supone que procesa bytes nulos correctamente). Sin embargo, POSIX no especifica claramente cómo se supone que debe lidiar con la entrada que no es una secuencia de caracteres. (Si fuera un implementador, pasaría secuencias de bytes no válidas sin modificarlas (o las eliminaría con -s), y plantearía un defecto con el comité estándar.) Evidentemente, el tr de macOS se queja de ellas.
Gilles 'SO- deja de ser malvado'
13

Supongo que su mapa de caracteres de las configuraciones regionales es UTF-8, por lo que tendrá problemas con los archivos binarios. Simplemente cambie a la configuración regional C:

LC_ALL=C tr '\r' '\n' < target-file | LC_ALL=C grep search-string
vinc17
fuente
puede usar paréntesis para evitar especificar el idioma dos veces. LC_ALL=C ( tr '\r' '\n' < target-file | grep search-string ). Sin embargo, el docx no es C local. Es utf16 y está comprimido y es complejo, y nadie lo sabe. Me gustaría utilizar una herramienta que puede convertirlo a un formato diferente que puede procesar, por ejemplo, html u odt (odt también está comprimido, pero está bien definido y es fácil de interpretar).
ctrl-alt-delor
1
La sintaxis con los corchetes (paréntesis) no funciona con todos los shells (no bash, ni zsh, ni guión). Luego, con respecto al archivo MS Word, depende. Tengo algunos de esos archivos donde el stringscomando da texto claro.
vinc17
Alternativamente, ( export LC_ALL=C; tr '\r' '\n' < target-file | grep search-string; )debería funcionar.
vinc17
1
stringstiene superpoderes: puede leer archivos que no son solo utf-8 o texto ascii.
ctrl-alt-delor
Perdón por ()lo que pensé que funcionaría, gracias a @ vinc17 por una solución.
ctrl-alt-delor