J'ai des vidages de base de données d'un système Windows sur ma boîte. Ce sont des fichiers texte. J'utilise cygwin pour les parcourir. Il semble s'agir de fichiers en texte brut; Je les ouvre avec des éditeurs de texte tels que le bloc-notes et le wordpad et ils ont l'air lisibles. Cependant, lorsque je lance grep sur eux, cela dit binary file foo.txt matches
.
J'ai 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 qu'est-ce qui fait que grep considère ces fichiers comme binaires? Le caractère NUL
? Y a-t-il un drapeau sur le système de fichiers? Que dois-je changer pour que grep me montre les correspondances de ligne?
S'il y a un caractère NUL
n'importe 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
pour éliminer tout null en premier, puis pour rechercher dans le fichier.
grep -a
a fonctionné pour moi:
$ grep --help
[...]
-a, --text equivalent to --binary-files=text
Vous pouvez utiliser l'utilitaire strings
pour extraire le contenu texte de n'importe quel fichier, puis le diriger via grep
, comme ceci: strings file | grep pattern
.
GNU grep 2.24 RTFS
Conclusion: 2 et 2 cas uniquement:
NUL
, par exemple printf 'a\0' | grep 'a'
erreur de codage selon 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: TF-8 - Description | en.wikipedia.org
De plus, comme mentionné par Stéphane Chazelas Qu'est-ce qui fait que grep considère un fichier comme binaire? | Unix & Linux Stack Exchange , ces vérifications ne sont effectuées que jusqu'à la première lecture du tampon de longueur TODO.
Uniquement jusqu'à la première lecture du tampon
Donc, si une erreur NUL ou d'encodage se produit au milieu d'un fichier très volumineux, elle peut être de toute façon saluée.
J'imagine que c'est pour des raisons de performances.
Par exemple: ceci imprime la ligne:
printf '%10000000s\n\x80a' | grep 'a'
mais cela ne signifie pas:
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. 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 ne fait que 1 octet 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 d'erreur stderr est codé:
git grep 'Binary file'
Nous amè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 arrivés à la conclusion.
encoding_error_output
La reconnaissance rapide de 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;
alors juste 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.
A FAIRE quand nlines_first_null < nlines
Peut-il jamais être faux? Je suis devenu paresseux.
[~ # ~] posix [~ # ~]
Ne définit pas d'options binaires grep - recherche dans un fichier un modèle | pubs.opengroup.org et GNU grep ne le documente pas, donc RTFS est le seul moyen .
Un de mes fichiers texte était soudainement considéré comme binaire par grep:
$ file foo.txt
foo.txt: ISO-8859 text
La solution consistait à le convertir en utilisant iconv
:
iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
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.
Note que le binaire peut juste être une solution de secours. Parfois, les fichiers avec un codage é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
Répondant en fait à la question "Qu'est-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; iconv
sortie m'a indiqué les numéros de ligne et de colonne de ces caractères
Dans le cas de NUL
caractères, iconv
les considérera comme normaux et n'imprimera pas ce type de sortie, donc cette méthode ne convient pas
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 voient comme binaire.
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
. Puis dans vi tapez :1,$s/^@//g
pour supprimer le ^@
personnages. Répétez cette commande pour ^M
.
Avertissement: pour obtenir les caractères de contrôle "bleus", appuyez sur Ctrl+v puis Ctrl+M ou Ctrl+@. Ensuite, enregistrez et quittez vi.