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
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, ungrep 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 unNUL
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 exempleprintf "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
- Plus précisément, erreur dencodage selon C99 ‘ s
mbrlen()
. Exemple et interprétation de la source sur: unix.stackexchange.com/a/276028/32558
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.
--null-data
peut être utile siNUL
est le délimiteur.