tr se plaint de «séquence d'octets illégaux»

24

Je suis tout nouveau sous UNIX et j'utilise "La ligne de commande Mac OS X" de Kirk McElhearn pour m'enseigner quelques commandes.

J'essaie d'utiliser tret greppour pouvoir rechercher des chaînes de texte dans un document Word MS-Office standard.

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

Mais tout cela revient:

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$ 

J'ai en fait exécuté la même ligne sur un script que j'ai créé viet il effectue correctement la recherche.

user74886
la source
Je ne vois pas pourquoi tr se plaindrait, avez-vous tapé la même chose que vous avez posé dans la question? grep ne trouvera pas ce que vous voulez, xdoc est une norme mal définie. Personne ne sait vraiment ce qu'il y a sur ces fichiers, les gens l'ont inversé, apparemment, la norme n'était d'aucune aide.
ctrl-alt-delor

Réponses:

29

grepest un outil de traitement de texte. Il s'attend à ce que leur entrée soit des fichiers texte . Il semble que la même chose vaut pour trmacOS (même s'il trest censé prendre en charge les fichiers binaires).

Les ordinateurs stockent les données sous forme de séquences d' octets . Un texte est une séquence de caractères. Il existe plusieurs façons de coder les caractères sous forme d'octets, appelés codages de caractères . L'encodage de caractères standard de facto dans la plupart du monde, en particulier sur OSX, est UTF-8 , qui est un encodage pour le jeu de caractères Unicode . Il n'y a que 256 octets possibles, mais plus d'un million de caractères Unicode possibles, de sorte que la plupart des caractères sont codés sur plusieurs octets. UTF-8 est un codage de longueur variable: selon le caractère, il peut prendre de un à quatre octets pour coder un caractère. Certaines séquences d'octets ne représentent aucun caractère en UTF-8. Par conséquent, il existe des séquences d'octets qui ne sont pas des fichiers texte UTF-8 valides.

trse plaint car il a rencontré une telle séquence d'octets. Il s'attend à voir un fichier texte encodé en UTF-8, mais il voit des données binaires qui ne sont pas des UTF-8 valides.

Un document Microsoft Word n'est pas un fichier texte: c'est un document de traitement de texte. Les formats de document de traitement de texte codent non seulement le texte, mais également le formatage, les images incorporées, etc. Le format Word, comme la plupart des formats de traitement de texte, n'est pas un fichier texte.

Vous pouvez demander aux outils de traitement de texte de fonctionner sur des octets en modifiant les paramètres régionaux . Plus précisément, sélectionnez les paramètres régionaux «C», ce qui signifie essentiellement «rien d'extraordinaire». Sur la ligne de commande, vous pouvez choisir les paramètres régionaux avec des variables d'environnement .

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

Cela n'émettra aucune erreur, mais ne fera rien d'utile non plus car il target-files'agit toujours d'un fichier binaire qui ne contiendra probablement pas la plupart des chaînes de recherche que vous spécifierez.

Soit dit en passant, ce tr '\r' '\n'n'est pas une commande très utile à moins qu'il ne reste des fichiers texte de Mac OS 9 ou plus. \r(retour chariot) était le séparateur de nouvelle ligne dans Mac OS avant Mac OS X. Depuis OSX, le séparateur de nouvelle ligne est \n( saut de ligne, la norme Unix) et les fichiers texte ne contiennent pas de retour chariot. Windows utilise la séquence de deux caractères CR-LF pour représenter les sauts de ligne; tr -d '\r'convertirait un fichier texte Windows en un fichier texte Unix / Linux / OSX.

Alors, comment pouvez-vous rechercher dans un document Word à partir de la ligne de commande? Un .docxdocument Word est en fait une archive zip contenant plusieurs fichiers, les principaux étant en XML .

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

Mac OS X inclut l' utilitaire zipgrep pour rechercher à l'intérieur des fichiers zip.

zipgrep DeCSS Position-Paper-Final-Version.docx

Le résultat ne sera pas très lisible car les fichiers XML au format docx se composent principalement d'une énorme ligne. Si vous souhaitez rechercher à l'intérieur du corps du texte du document, extrayez le fichier word/document.xmlde l'archive. Notez qu'en plus du texte du document, ce fichier contient un balisage XML qui représente la structure du document. Vous pouvez masser un peu le balisage XML avec sedpour le diviser en lignes gérables.

unzip -p Position-Paper-Final-Version.docx word/document.xml |
sed -e 's/></>\n</g' |
grep DeCSS
Gilles 'SO- arrête d'être méchant'
la source
1
+1 pour un bon résumé et des bits supplémentaires. J'ai une chose à dire cependant. Pour formater le xml, vous pouvez l'utiliser xml_ppen paquet xml-twig-toolssur Debian Gnu + Linux (je ne connais pas de mac).
ctrl-alt-delor
2
Excel pour Mac 2011 enregistre les fichiers CSV avec des fins de ligne \ r, donc cette invocation tr est en fait assez pertinente et utile.
Noah Yetter
1
Tout comme Outlook pour Mac 2011 lorsque vous exportez une liste de contacts délimitée par des tabulations.
Ivan X
1
Eh bien, je n'ai pas assez de réputation pour dévaloriser cela, mais cette réponse est tout à fait incorrecte. Il commence par " tr[...] s'attendre à ce que leur entrée soit des fichiers texte."; tandis que la spécification POSIX indique clairement "L'entrée standard peut être n'importe quel type de fichier." . Veuillez corriger votre réponse.
7heo.tk
@ 7heo.tk «cette réponse est tout à fait incorrecte» est une exagération grossière, mais vous avez raison, trest censée traiter l'entrée binaire (en particulier, elle est censée traiter correctement les octets nuls). Cependant, POSIX ne spécifie pas clairement comment il est censé traiter les entrées qui ne sont pas une séquence de caractères. (Si j'étais un implémenteur, je passerais des séquences d'octets non valides par le biais de non modifiés (ou les supprimerais avec -s) et soulèverais un défaut avec le comité standard.) Évidemment, le tr de macOS s'en plaint.
Gilles 'SO- arrête d'être méchant'
13

Je suppose que votre charmap des locales est UTF-8, de sorte que vous aurez des problèmes avec les fichiers binaires. Passez simplement en locale C:

LC_ALL=C tr '\r' '\n' < target-file | LC_ALL=C grep search-string
vinc17
la source
vous pouvez utiliser des crochets pour éviter de spécifier deux fois la langue. LC_ALL=C ( tr '\r' '\n' < target-file | grep search-string ). Cependant le docx n'est pas C local. Est utf16 et zippé et complexe et n'importe qui devine. Je dirais que j'utilise un outil qui peut le convertir dans un format différent que vous pouvez traiter, par exemple html ou odt (odt est également compressé, mais bien défini et facile à interpréter).
ctrl-alt-delor
1
La syntaxe avec les crochets (parenthèses) ne fonctionne pas avec tous les shells (pas bash, pas zsh, pas tiret). Ensuite, concernant le fichier MS Word, cela dépend. J'ai certains de ces fichiers où la stringscommande donne du texte clair.
vinc17
Sinon, ( export LC_ALL=C; tr '\r' '\n' < target-file | grep search-string; )devrait fonctionner.
vinc17
1
stringsa des super pouvoirs: il peut lire des fichiers qui ne sont pas seulement du texte utf-8 ou ascii.
ctrl-alt-delor
Désolé pour la ()chose que je pensais que cela fonctionnerait, merci à @ vinc17 pour un correctif.
ctrl-alt-delor