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, wennNUL
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 einegrep 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 einemNUL
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
, zprintf "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 zu0x7F
). Ü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
- Genauer gesagt, Codierungsfehler gemäß C99 ‚ s
mbrlen()
. Beispiel und Quelleninterpretation unter: unix.stackexchange.com/a/276028/32558
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.