web-dev-qa-db-fra.com

Qu'est-ce qui fait que grep considère un fichier comme binaire?

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?

203
user394

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.

139
bbaja42

grep -a a fonctionné pour moi:

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

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.

21
holgero

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
6
zzapper

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

5
klapaucius

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

2
golimar

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.

2
Joan Pontius

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.

1
Not Sure