Ich habe einige Datenbank-Dumps von einem Windows-System auf meiner Box. Sie sind Textdateien. Ich verwende Cygwin, um sie zu durchsuchen. Dies scheinen reine Textdateien zu sein. Ich öffne sie mit Texteditoren wie Editor und Wordpad und sie sehen lesbar aus. Wenn ich jedoch Grep auf ihnen ausführe, wird binary file foo.txt matches.

Ich habe festgestellt, dass die Dateien einige ASCII NUL -Zeichen enthalten, von denen ich glaube, dass sie Artefakte aus dem Datenbankspeicherauszug sind.

Warum betrachtet grep diese Dateien als binär? Das Zeichen NUL Gibt es ein Flag im Dateisystem? Was muss ich ändern, um grep zu erhalten? Zeigen Sie mir die Zeilenübereinstimmungen?

Kommentare

  • --null-data kann nützlich sein, wenn NUL ist das Trennzeichen.

Antwort

Wenn es eine NUL Zeichen an einer beliebigen Stelle in der Datei, grep betrachtet es als Binärdatei.

Möglicherweise kann eine Problemumgehung wie diese cat file | tr -d "\000" | yourgrep beseitigt werden alle null zuerst und dann zum Durchsuchen der Datei.

Kommentare

  • … oder verwenden Sie -a / --text, zumindest mit GNU grep.
  • @derobert: Auf einigen (älteren) Systemen sieht grep Zeilen, aber seine Ausgabe schneidet jede übereinstimmende Zeile bei der ersten ab NUL (wahrscheinlich, weil es C ‚ s printf aufruft und ihm die übereinstimmende Zeile gibt?). Auf einem solchen System gibt eine grep cmd .sh_history so viele Leerzeilen zurück, wie Zeilen vorhanden sind, die mit ‚ cmd ‚, da jede Zeile von sh_history ein bestimmtes Format mit einem NUL am Anfang jeder Zeile hat. (aber Ihr Kommentar “ zumindest auf GNU grep “ wird wahrscheinlich wahr. Ich ‚ Ich habe momentan keinen zur Hand, um ihn zu testen, aber ich gehe davon aus, dass sie damit gut umgehen.)
  • Ist das Vorhandensein eines NUL-Zeichens das einzige Kriterium? Ich bezweifle das. Es ist wahrscheinlich schlauer als das ‚. Alles, was außerhalb des Bereichs von Ascii 32-126 liegt, würde ich vermuten, aber wir ‚ müssten uns den Quellcode ansehen, um sicherzugehen.
  • Meine Informationen waren von der Manpage der spezifischen grep-Instanz. Ihr Kommentar zur Implementierung ist gültig, Quelle übertrumpft Dokumente.
  • Ich hatte eine Datei, die grep auf cygwin als binär betrachtete, weil sie stattdessen einen langen Bindestrich (0x96) hatte ein regulärer ASCII-Bindestrich / Minus (0x2d). Ich denke, diese Antwort hat das Problem mit OP ‚ behoben, aber es scheint unvollständig zu sein.

Antwort

grep -a hat bei mir funktioniert:

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

Kommentare

  • Dies ist die beste und kostengünstigste Antwort IMO.
  • Aber nicht POSIX-konform
  • Würde es Ihnen etwas ausmachen zu erklären, warum dies nicht der Fall ist? Es wäre gut, dies für alle von uns klar zu machen, die diese Antwort als Option finden. Danke :).
  • Hey, ich ‚ bin ein ZWEITES Mal hierher gekommen, um dieses LOL neu zu lernen. Ein französischer Akzent (diakritisch) im Text führte dazu, dass grep

Antwort

Sie können das strings Dienstprogramm zum Extrahieren des Textinhalts aus einer beliebigen Datei und zum Weiterleiten durch grep wie folgt: strings file | grep pattern.

Kommentare

  • Ideal zum Erfassen von Protokolldateien, die teilweise beschädigt sein könnten
  • ja, manchmal binäre gemischte Protokollierung passiert auch. Dies ist gut.

Antwort

GNU grep 2.24 RTFS

Schlussfolgerung: Nur 2 und 2 Fälle:

  • NUL, z printf "a\0" | grep "a"

  • Codierungsfehler gemäß C99 mbrlen(), z. B.:

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

    , weil \x80 nicht das erste Byte eines UTF-8-Unicode-Punkts sein kann: UTF-8 – Beschreibung | en.wikipedia.org

Wie von Stéphane Chazelas erwähnt Was lässt grep eine Datei in Betracht ziehen? binär sein? | Unix & Linux Stack Exchange werden diese Überprüfungen nur bis zum ersten Pufferlesevorgang der Länge TODO durchgeführt.

Nur bis zum ersten Puffer lesen

Wenn also ein NUL- oder Codierungsfehler in der Mitte einer sehr großen Datei auftritt, kann dies passieren Wie auch immer.

Ich stelle mir das aus Leistungsgründen vor.

Beispiel: Hiermit wird die folgende Zeile gedruckt:

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

dies jedoch nicht:

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

Die tatsächliche Puffergröße hängt davon ab, wie die Datei gelesen wird. Z.B.Vergleichen Sie:

export LC_CTYPE="en_US.UTF-8" (printf "\n\x80a") | grep "a" (printf "\n"; sleep 1; printf "\x80a") | grep "a" 

Mit der sleep wird die erste Zeile an grep übergeben, auch wenn es nur 1 Byte ist lang, weil der Prozess in den Ruhezustand wechselt und der zweite Lesevorgang nicht prüft, ob die Datei binär ist.

RTFS

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

Suchen Sie, wo die stderr-Fehlermeldung codiert ist:

git grep "Binary file" 

Führt uns zu /src/grep.c:

if (!out_quiet && (encoding_error_output || (0 <= nlines_first_null && nlines_first_null < nlines))) { printf (_("Binary file %s matches\n"), filename); 

Wenn diese Variablen gut benannt waren, kamen wir im Grunde zu dem Schluss.

encoding_error_output

Schnelle Suche nach encoding_error_output zeigt, dass der einzige Codepfad, der ihn ändern kann, über buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs); if ((size_t) -2 <= clen) return true; 

und dann nur man mbrlen.

nlines_first_null und nlines

Initialisiert als:

intmax_t nlines_first_null = -1; nlines = 0; 

Wenn also eine Null gefunden wird, wird 0 <= nlines_first_null wahr.

TODO wann kann nlines_first_null < nlines jemals falsch sein? Ich wurde faul.

POSIX

Definiert keine binären Optionen grep – Durchsucht eine Datei nach einem Muster | pubs.opengroup.org und GNU grep dokumentiert es nicht, daher ist RTFS der einzige Weg.

Kommentare

  • Beeindruckende Erklärung !
  • Beachten Sie, dass die Überprüfung auf gültiges UTF-8 nur in UTF-8-Gebietsschemas erfolgt. Beachten Sie auch, dass die Überprüfung nur für den ersten aus der Datei gelesenen Puffer durchgeführt wird, der für eine reguläre Datei auf meinem System 32768 Byte zu sein scheint, für eine Pipe oder einen Socket jedoch nur ein Byte betragen kann. Vergleichen Sie beispielsweise (printf '\n\0y') | grep y mit (printf '\n'; sleep 1; printf '\0y') | grep y.
  • @St é phaneChazelas “ Beachten Sie, dass die Überprüfung auf gültiges UTF-8 nur in UTF-8-Gebietsschemas erfolgt. „: Meinen Sie die export LC_CTYPE='en_US.UTF-8' wie in meinem Beispiel oder etwas anderes? Buf las: erstaunliches Beispiel, hinzugefügt, um zu antworten. Sie haben die Quelle offensichtlich mehr gelesen als ich, erinnert mich an diese Hacker-Koans “ Der Student war erleuchtet “ 🙂
  • Ich habe ‚ auch nicht ins Detail geschaut, sondern hat kürzlich
  • @CiroSantilli 法轮功 文件 六四 事件 法轮功 gegen welche Version von GNU grep haben Sie getestet?

Antwort

Eine meiner Textdateien wurde plötzlich von grep als binär angesehen:

$ file foo.txt foo.txt: ISO-8859 text 

Die Lösung bestand darin, es mithilfe von iconv zu konvertieren:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt 

Kommentare

  • Das ist mir auch passiert. Die Ursache war insbesondere ein ISO-8859-1-codierter, nicht unterbrechender Speicherplatz, den ich durch einen regulären Speicherplatz ersetzen musste, damit grep in der Datei suchen konnte.
  • grep 2.21 behandelt ISO -8859 Textdateien, als wären sie binär, fügen Sie vor dem Befehl grep export LC_ALL = C hinzu.
  • @netawater Danke! Dies ist z.B. der Fall, wenn Sie so etwas wie M ü ller in einer Textdatei haben. Das ‚ s 0xFC hexadezimal, also außerhalb des Bereichs grep würde es für utf8 erwarten (bis zu 0x7F). Überprüfen Sie mit printf ‚ a \ x7F ‚ | grep ‚ a ‚ wie Ciro oben beschrieben hat.

Antwort

Die Datei /etc/magic oder /usr/share/misc/magic enthält eine Liste von Sequenzen, die der Befehl file wird zum Bestimmen des Dateityps verwendet.

Beachten Sie , dass Binärdateien möglicherweise nur eine Fallback-Lösung sind. Manchmal werden Dateien mit seltsamer Codierung auch als binär betrachtet.

grep unter Linux bietet einige Optionen für die Verarbeitung von binären Dateien wie --binary-files oder -U / --binary

Kommentare

Antwort

Einer meiner Schüler hatte dieses Problem. In grep in Cygwin ist ein Fehler aufgetreten. Wenn die Datei Nicht-Ascii-Zeichen enthält, wird sie von grep und egrep als binär angezeigt.

Kommentare

  • Das klingt nach einer Funktion, nicht nach einem Fehler.Insbesondere, wenn es eine Befehlszeilenoption gibt, um es zu steuern (-a / –text)

Antwort

Wenn Sie die Frage „Was bringt grep dazu, eine Datei als binär zu betrachten?“ Beantworten, können Sie iconv verwenden:

$ iconv < myfile.java iconv: (stdin):267:70: cannot convert 

In meinem Fall gab es spanische Zeichen, die in Texteditoren korrekt angezeigt wurden, aber grep betrachtete sie als binär. Die Ausgabe iconv zeigte mir die Zeilen- und Spaltennummern dieser Zeichen.

Bei NUL Zeichen iconv betrachtet sie als normal und druckt diese Art von Ausgabe nicht, sodass diese Methode nicht geeignet ist.

Antwort

Ich hatte das gleiche Problem. Ich habe vi -b [filename] verwendet, um die hinzugefügten Zeichen anzuzeigen. Ich habe die Steuerzeichen ^@ und ^M gefunden. Geben Sie dann in vi :1,$s/^@//g ein, um die Zeichen ^@ zu entfernen. Wiederholen Sie diesen Befehl für ^M.

Warnung: Um die „blauen“ Steuerzeichen zu erhalten, drücken Sie Strg + v und dann Strg + M oder Strg + @ . Speichern und beenden Sie dann vi.

Antwort

Ich hatte auch dieses Problem, aber in meinem Fall wurde es verursacht, wenn eine übereinstimmende Zeile vorliegt zu lang.

file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines 

grep würde die gesamte Datei mit vielen Mustern durchlaufen, aber wenn ein Muster mit a übereinstimmt “ sehr lange Zeile “ wurde mit Binary file myfile.txt matches gestoppt.

Das Hinzufügen von -a löst dieses Problem ebenfalls, aber das Vorparsen der Datei auf NULL oder andere ungültige Zeichen hätte keine Auswirkung (es gibt keine, sonst würde grep für andere Muster nicht vollständig sein). In diesem Fall hatte die fehlerhafte Zeile mehr als 25.000 Zeichen!

Was ich nicht verstehe, ist, warum es nur passiert, wenn grep versucht, die Zeile zurückzugeben, und nicht, wenn es verarbeitet es auf der Suche nach anderen Mustern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.