Jai des sauvegardes de bases de données dun système Windows sur ma boîte. Ce sont des fichiers texte. Jutilise cygwin pour les greper. Ceux-ci semblent être des fichiers de texte brut; je les ouvre avec des éditeurs de texte tels que le bloc-notes et le pavé de mots et ils semblent lisibles. Cependant, lorsque jexécute grep sur eux, le message binary file foo.txt matches.

Jai remarqué que les fichiers contiennent des caractères ascii NUL, qui, je crois, sont des artefacts du vidage de la base de données.

Alors, quest-ce qui fait que grep considère ces fichiers comme binaires? Le caractère NUL? Y a-t-il un indicateur sur le système de fichiers? Que dois-je changer pour obtenir grep montre-moi la ligne correspond?

Commentaires

  • --null-data peut être utile si NUL est le délimiteur.

Réponse

Sil y a un NUL caractère nimporte où dans le fichier, grep le considérera comme un fichier binaire.

Il pourrait y avoir une solution de contournement comme celle-ci cat file | tr -d "\000" | yourgrep à éliminer tout dabord nul, et puis pour rechercher dans le fichier.

Commentaires

  • … ou utilisez -a / --text, au moins avec GNU grep.
  • @derobert: en fait, sur certains systèmes (plus anciens), grep voit les lignes, mais sa sortie tronquera chaque ligne correspondante au début NUL (probablement parce quil appelle C ‘ s printf et lui donne la ligne correspondante?). Sur un tel système, un grep cmd .sh_history renverra autant de lignes vides que de lignes correspondant à ‘ cmd ‘, car chaque ligne de sh_history a un format spécifique avec un NUL au début de chaque ligne. (mais votre commentaire  » au moins sur GNU grep  » se réalise probablement. Je ne ‘ Jen ai un sous la main pour le tester, mais je pense quils gèrent bien cela)
  • La présence dun caractère NUL est-elle le seul critère? Jen doute. Il ‘ est probablement plus intelligent que cela. Tout ce qui se situe en dehors de la plage Ascii 32-126 serait à mon avis, mais nous ‘ devons regarder le code source pour être sûr.
  • Mes informations étaient à partir de la page de manuel de linstance grep spécifique. Votre commentaire sur limplémentation est valide, la source lemporte sur les documents.
  • Javais un fichier qui grep sur cygwin considéré comme binaire car il avait un long tiret (0x96) au lieu de un trait dunion ASCII / moins (0x2d). Je suppose que cette réponse a résolu le problème de lOP ‘, mais il semble quil soit incomplet.

Réponse

grep -a a fonctionné pour moi:

$ grep --help [...] -a, --text equivalent to --binary-files=text 

Commentaires

  • Cest la meilleure réponse IMO, la moins chère.
  • Mais non conforme à POSIX
  • Pourriez-vous expliquer pourquoi ce nest pas le cas? Il serait bon que ce soit clair, pour nous tous qui trouvons cette réponse comme une option. Merci :).
  • Salut, ‘ suis venu ici une SECONDE fois pour réapprendre cette LOL. Un accent français (diacritique) dans le texte faisait barf de grep

Réponse

Vous pouvez utiliser le strings pour extraire le contenu texte de nimporte quel fichier, puis le diriger vers grep, comme ceci: strings file | grep pattern.

Commentaires

  • Idéal pour grepping des fichiers journaux qui pourraient être partiellement corrompus
  • oui, parfois journalisation mixte binaire arrive aussi. Cest bien.

Réponse

GNU grep 2.24 RTFS

Conclusion: 2 et 2 cas uniquement:

  • NUL, par exemple printf "a\0" | grep "a"

  • erreur de codage selon le C99 mbrlen(), par exemple:

    export LC_CTYPE="en_US.UTF-8" printf "a\x80" | grep "a" 

    car \x80 ne peut pas être le premier octet dun point Unicode UTF-8: UTF-8 – Description | fr.wikipedia.org

De plus, comme mentionné par Stéphane Chazelas Quest-ce qui fait que grep considère un fichier comme être binaire? | Unix & Linux Stack Exchange , ces vérifications ne sont effectuées que jusquà la première lecture de tampon de longueur TODO.

Seulement jusquau premier tampon lu

Donc, si une erreur NUL ou dencodage se produit au milieu dun fichier très volumineux, cela peut être grepped de toute façon.

Jimagine que cest pour des raisons de performances.

Ex: ceci imprime la ligne:

printf "%10000000s\n\x80a" | grep "a" 

mais ce nest pas le cas:

printf "%10s\n\x80a" | grep "a" 

La taille réelle du tampon dépend de la façon dont le fichier est lu. Par exemple.compare:

export LC_CTYPE="en_US.UTF-8" (printf "\n\x80a") | grep "a" (printf "\n"; sleep 1; printf "\x80a") | grep "a" 

Avec le sleep, la première ligne est passée à grep même si elle ne fait que 1 octet long car le processus se met en veille et la deuxième lecture ne vérifie pas si le fichier est binaire.

RTFS

git clone git://git.savannah.gnu.org/grep.git cd grep git checkout v2.24 

Trouvez où le message derreur stderr est encodé:

git grep "Binary file" 

Nous mène à /src/grep.c:

if (!out_quiet && (encoding_error_output || (0 <= nlines_first_null && nlines_first_null < nlines))) { printf (_("Binary file %s matches\n"), filename); 

Si ces variables étaient bien nommées, nous sommes en gros arrivés à la conclusion.

encoding_error_output

Grepping rapide pour encoding_error_output montre que le seul chemin de code qui peut le modifier passe par buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs); if ((size_t) -2 <= clen) return true; 

puis juste man mbrlen.

nlines_first_null et nlines

Initialisé comme:

intmax_t nlines_first_null = -1; nlines = 0; 

donc quand un nul est trouvé 0 <= nlines_first_null devient vrai.

TODO quand peut nlines_first_null < nlines a déjà été faux? Je suis paresseux.

POSIX

Ne définit pas les options binaires grep – recherche un fichier pour un motif | pubs.opengroup.org , et GNU grep ne le documente pas, donc RTFS est le seul moyen.

Commentaires

  • Explication impressionnante !
  • Notez que la vérification de la validité UTF-8 se produit uniquement dans les paramètres régionaux UTF-8. Notez également que la vérification nest effectuée que sur le premier tampon lu dans le fichier qui pour un fichier normal semble être de 32768 octets sur mon système, mais pour un tube ou un socket peut être aussi petit quun octet. Comparez (printf '\n\0y') | grep y avec (printf '\n'; sleep 1; printf '\0y') | grep y par exemple.
  • @St é phaneChazelas  » Notez que la vérification de la validité UTF-8 ne se produit que dans les paramètres régionaux UTF-8 « : voulez-vous dire à propos de export LC_CTYPE='en_US.UTF-8' comme dans mon exemple, ou autre chose? Buf lu: exemple étonnant, ajouté pour répondre. Vous avez évidemment lu la source plus que moi, cela me rappelle ces koans hacker  » Lélève était éclairé  » 🙂
  • Je nai ‘ pas regardé en détail non plus, mais a fait très récemment
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 avec quelle version de GNU grep avez-vous testé?

Réponse

Un de mes fichiers texte a soudainement été considéré comme binaire par grep:

$ file foo.txt foo.txt: ISO-8859 text 

La solution était de le convertir en utilisant iconv:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt 

Commentaires

  • Cela mest arrivé aussi. En particulier, la cause était un espace insécable codé ISO-8859-1, que jai dû remplacer par un espace régulier afin que grep recherche dans le fichier.
  • grep 2.21 traite ISO -8859 fichiers texte comme sils étaient binaires, ajoutez export LC_ALL = C avant la commande grep.
  • @netawater Merci! Cest par exemple le cas si vous avez quelque chose comme M ü ller dans un fichier texte. Cet ‘ s 0xFC hexadécimal, donc en dehors de la plage que grep attendrait pour utf8 (jusquà 0x7F). Vérifiez avec printf ‘ a \ x7F ‘ | grep ‘ a ‘ comme décrit par Ciro ci-dessus.

Réponse

Le fichier /etc/magic ou /usr/share/misc/magic a une liste de séquences que la commande file utilise pour déterminer le type de fichier.

Notez que le binaire peut être juste une solution de secours. Parfois, les fichiers avec un encodage étrange sont également considérés comme binaires.

grep sur Linux a quelques options pour gérer les fichiers binaires comme --binary-files ou -U / --binary

Commentaires

Réponse

Un de mes élèves a eu ce problème. Il y a un bogue dans grep dans Cygwin. Si le fichier contient des caractères non Ascii, grep et egrep le considèrent comme binaire.

Commentaires

  • Cela ressemble à une fonctionnalité, pas à un bogue.Surtout quil existe une option en ligne de commande pour le contrôler (-a / –text)

Answer

En réponse à la question « Quest-ce qui fait que grep considère un fichier comme binaire? », Vous pouvez utiliser iconv:

$ iconv < myfile.java iconv: (stdin):267:70: cannot convert 

Dans mon cas, il y avait des caractères espagnols qui apparaissaient correctement dans les éditeurs de texte mais grep les considérait comme binaires; La sortie iconv ma indiqué les numéros de ligne et de colonne de ces caractères

Dans le cas des caractères NUL, iconv les considérera comme normales et nimprimera pas ce type de sortie donc cette méthode ne convient pas

Réponse

Jai eu le même problème. Jai utilisé vi -b [filename] pour voir les caractères ajoutés. Jai trouvé les caractères de contrôle ^@ et ^M. Puis dans vi tapez :1,$s/^@//g pour supprimer les caractères ^@. Répétez cette commande pour ^M.

Attention: pour obtenir les caractères de contrôle « bleus » appuyez sur Ctrl + v puis Ctrl + M ou Ctrl + @ . Puis enregistrez et quittez vi.

Réponse

Jai également eu ce problème mais dans mon cas, il a été causé lorsquune ligne correspondante est trop long.

file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines 

grep parcourrait tout le fichier bien avec de nombreux modèles mais quand un modèle correspondait à un  » très longue ligne  » elle sest arrêtée avec Binary file myfile.txt matches.

Lajout de -a résout également ce problème, mais la pré-analyse du fichier pour NULL ou dautres caractères invalides naurait aucun effet (il ny en a aucun sinon grep ne serait pas terminé pour les autres modèles). Dans ce cas, la ligne incriminée contenait plus de 25 000 caractères!

Ce que je ne comprends pas, cest pourquoi cela narrive que lorsque grep essaie de renvoyer la ligne et non quand le traite à la recherche dautres modèles.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *