Qu'est-ce qui fait que grep considère un file comme étant binary?

J'ai des décharges de database d'un système de Windows sur ma boîte. Ce sont des files text. J'utilise cygwin pour grep à travers eux. Ceux-ci semblent être des files text en clair; Je les ouvre avec des éditeurs de text tels que bloc-notes et wordpad et ils sont lisibles. Cependant, quand binary file foo.txt matches grep sur eux, il dira des binary file foo.txt matches .

J'ai remarqué que les files contiennent des caractères NUL ASCII, qui, je crois, sont des artefacts du vidage de la database.

Alors, pourquoi grep considère ces files comme étant binarys? Le caractère NUL ? Y a-t-il un drapeau sur le système de files? Que dois-je changer pour que grep me montre les correspondances de ligne?

S'il existe un caractère NUL dans le file, grep le considérera comme un file binary.

Il pourrait y avoir une solution de contournement comme ce cat file | tr -d '\000' | yourgrep cat file | tr -d '\000' | yourgrep cat file | tr -d '\000' | yourgrep pour éliminer tout d'abord null, puis pour searchr dans le file.

grep -a travaillé pour moi:

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

Vous pouvez utiliser l'utilitaire ssortingngs pour extraire le contenu du text à partir de n'importe quel file, puis le transporter via grep , comme ceci: ssortingngs file | grep pattern ssortingngs file | grep pattern .

GNU grep 2.24 RTFS

Conclusion: 2 et 2 cas seulement:

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

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

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

    parce que \x80 ne peut pas être le premier octet d'un point Unicode UTF-8: https://en.wikipedia.org/wiki/UTF-8#Description

Seulement jusqu'au premier tampon lu

Comme le mentionne Stéphane Chazelas , ces vérifications ne sont effectuées que jusqu'au premier tampon lu, donc si une erreur NUL ou d'enencoding se produit au milieu d'un file très volumineux, il pourrait être grepé de toute façon.

J'imagine que c'est pour des raisons de performance.

Par exemple: cela imprime la ligne:

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

mais cela ne veut pas dire:

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

La taille réelle de la memory tampon dépend de la façon dont le file est lu. Par exemple comparer:

 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 n'a qu'un octet de long car le process se met en veille et la deuxième lecture ne vérifie pas si le file est binary.

RTFS

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

Trouvez où le message d'erreur stderr est codé:

 git grep 'Binary file' 

Nous conduit à /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 sums arrivés à la conclusion.

encoding_error_output

Grepping rapide pour encoding_error_output montre que le seul path 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; 

alors juste l' man mbrlen .

nlines_first_null et nlines

Initialisé comme:

 intmax_t nlines_first_null = -1; nlines = 0; 

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

TODO quand can nlines_first_null < nlines peut-il être faux? Je suis paresseux.

POSIX

Ne définit pas les options binarys http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html , et GNU grep ne le documente pas, donc RTFS est le seul moyen.

Le file /etc/magic ou /usr/share/misc/magic contient une list de séquences utilisées par le file commands pour déterminer le type de file.

Notez que binary peut être une solution de repli. Parfois, les files avec un encoding étrange sont considérés comme binarys aussi.

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

Un de mes files text était soudainement vu comme binary 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 

Un de mes étudiants avait ce problème. Il y a un bug dans grep dans Cygwin . Si le file a des caractères non-Ascii, grep et egrep voient comme binary.

En fait, en répondant à la question "Qu'est-ce qui fait que grep considère un file comme étant binary?", 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 text mais grep les considérait comme binarys; iconv sortie iconv m'a 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 normaux et n'imprimera pas ce type de sortie afin que cette méthode ne soit pas appropriée

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

Attention: Pour get les caractères de contrôle "bleus", appuyez sur Ctrl + v puis Ctrl + M ou Ctrl + @ . Ensuite, sauvegardez et quittez vi.