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.