Ik heb een aantal database-dumps van een Windows-systeem op mijn box. Het zijn tekstbestanden. Ik gebruik cygwin om er doorheen te grepen. Dit lijken platte tekstbestanden te zijn; ik open ze met teksteditors zoals kladblok en wordpad en ze zien er leesbaar uit. Als ik er echter grep op draai, staat er binary file foo.txt matches.

Ik heb gemerkt dat de bestanden enkele ascii NUL -tekens bevatten, die naar mijn mening artefacten zijn uit de database-dump.

Dus waarom beschouwt grep deze bestanden als binair? Het NUL karakter? Staat er een vlag op het bestandssysteem? Wat moet ik veranderen om grep naar laat me de regelovereenkomsten zien?

Reacties

  • --null-data kan nuttig zijn als NUL is het scheidingsteken.

Antwoord

Als er een NUL teken ergens in het bestand, grep beschouwt het als een binair bestand.

Er kan een oplossing als deze cat file | tr -d "\000" | yourgrep voorkomen alle nul eerst, en en vervolgens door het bestand te zoeken.

Opmerkingen

  • … of gebruik -a / --text, in ieder geval met GNU grep.
  • @derobert: eigenlijk, op sommige (oudere) systemen, ziet grep regels, maar de uitvoer zal elke overeenkomende regel bij de eerste afkappen NUL (waarschijnlijk omdat het C ‘ s printf aanroept en het de overeenkomende regel geeft?). Op zon systeem zal een grep cmd .sh_history net zoveel lege regels retourneren als er regels zijn die overeenkomen met ‘ cmd ‘, aangezien elke regel van sh_history een specifiek formaat heeft met een NUL aan het begin van elke regel. (maar je opmerking ” in ieder geval op GNU grep ” komt waarschijnlijk uit. Ik wil niet ‘ ik heb er momenteel geen om te testen, maar ik verwacht dat ze dit netjes afhandelen)
  • Is de aanwezigheid van een NUL-teken het enige criterium? Ik betwijfel het. Het ‘ is waarschijnlijk slimmer dan dat. Alles wat buiten het Ascii 32-126-bereik valt, zou mijn gok zijn, maar we ‘ zouden voor de zekerheid naar de broncode moeten kijken.
  • Mijn info was van de man-pagina van de specifieke grep-instantie. Uw opmerking over de implementatie is geldig, de bron overtreft docs.
  • Ik had een bestand dat grep op cygwin als binair beschouwde omdat het een lang streepje (0x96) had in plaats van een gewoon ASCII-streepje / minus (0x2d). Ik denk dat dit antwoord het probleem van OP ‘ heeft opgelost, maar het lijkt erop dat het onvolledig is.

Antwoord

grep -a werkte voor mij:

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

Reacties

  • Dit is het beste, minst dure antwoord IMO.
  • Maar niet POSIX-compatibel
  • Zou je willen uitleggen waarom dit niet zo is? Het zou goed zijn om het duidelijk te maken voor ons allemaal die dit antwoord als een optie beschouwen. Bedankt :).
  • Hallo, ik ben ‘ hier een TWEEDE keer gekomen om deze LOL opnieuw te leren. Een Frans accent (diakritisch) in de tekst zorgde ervoor dat grep barf

Answer

Je kunt de strings hulpprogramma om de tekstinhoud uit elk bestand te extraheren en deze vervolgens door grep te leiden, zoals dit: strings file | grep pattern.

Opmerkingen

  • Ideaal voor het grepen van logbestanden die gedeeltelijk beschadigd kunnen zijn
  • ja, soms binaire gemengde logboekregistratie gebeurt ook. Dit is goed.

Antwoord

GNU grep 2.24 RTFS

Conclusie: alleen 2 en 2 gevallen:

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

  • coderingsfout volgens de C99 mbrlen(), bijvoorbeeld:

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

    omdat \x80 niet de eerste byte kan zijn van een UTF-8 Unicode-punt: UTF-8 – Beschrijving | en.wikipedia.org

Verder, zoals vermeld door Stéphane Chazelas Wat maakt dat grep een bestand beschouwt binair zijn?Unix & Linux Stack Exchange , die controles worden alleen uitgevoerd tot aan de eerste gelezen buffer met een lengte TODO.

Alleen tot de eerste gelezen buffer

Dus als er een NUL of coderingsfout optreedt in het midden van een zeer groot bestand, kan dit worden toch gegrepen.

Ik veronderstel dat dit om prestatieredenen is.

Bijv .: dit drukt de regel af:

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

maar dit niet:

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

De werkelijke buffergrootte hangt af van hoe het bestand wordt gelezen. Bijv.vergelijk:

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

Met de sleep wordt de eerste regel doorgegeven aan grep, zelfs als deze maar 1 byte is lang omdat het proces in slaap valt en de tweede keer lezen niet controleert of het bestand binair is.

RTFS

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

Zoek waar het stderr-foutbericht is gecodeerd:

git grep "Binary file" 

Leidt ons naar /src/grep.c:

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

Als die variabelen een goede naam hadden, kwamen we in feite tot de conclusie.

encoding_error_output

Snelle grepping voor encoding_error_output laat zien dat het enige codepad dat het kan wijzigen door buf_has_encoding_errors:

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

gaat en dan alleen man mbrlen.

nlines_first_null en nlines

Geïnitialiseerd als:

intmax_t nlines_first_null = -1; nlines = 0; 

dus wanneer een null wordt gevonden, wordt 0 <= nlines_first_null waar.

TODO wanneer kan nlines_first_null < nlines ooit vals zijn? Ik werd lui.

POSIX

Definieert geen binaire opties grep – zoek in een bestand naar een patroon | pubs.opengroup.org , en GNU grep documenteert het niet, dus RTFS is de enige manier.

Reacties

  • Indrukwekkende uitleg !
  • Merk op dat de controle op geldige UTF-8 alleen plaatsvindt in UTF-8-landinstellingen. Merk ook op dat de controle alleen wordt uitgevoerd op de eerste buffer die uit het bestand wordt gelezen, dat voor een normaal bestand 32768 bytes op mijn systeem lijkt te zijn, maar voor een pipe of socket kan dit zo klein zijn als één byte. Vergelijk (printf '\n\0y') | grep y met (printf '\n'; sleep 1; printf '\0y') | grep y bijvoorbeeld.
  • @St é phaneChazelas ” Merk op dat de controle op geldige UTF-8 alleen plaatsvindt in UTF-8-landinstellingen “: bedoel je over de export LC_CTYPE='en_US.UTF-8' zoals in mijn voorbeeld, of iets anders? Buf gelezen: geweldig voorbeeld, toegevoegd om te beantwoorden. Je hebt de bron duidelijk meer gelezen dan ik, doet me denken aan die hacker koans ” De leerling werd ingelicht ” 🙂
  • Ik heb ‘ ook niet in detail gekeken, maar zeer recentelijk
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 tegen welke versie van GNU grep heb je getest?

Antwoord

Een van mijn tekstbestanden werd plotseling door grep als binair beschouwd:

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

De oplossing was om het te converteren met iconv:

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

Reacties

  • Dit is mij ook overkomen. In het bijzonder was de oorzaak een ISO-8859-1-gecodeerde niet-afbrekende spatie, die ik moest vervangen door een gewone spatie om grep in het bestand te laten zoeken.
  • grep 2.21 behandelt ISO -8859 tekstbestanden alsof ze binair zijn, voeg export LC_ALL = C toe vóór het grep-commando.
  • @netawater Bedankt! Dit is bijv. het geval als je zoiets als M ü ller in een tekstbestand hebt. Dat ‘ s 0xFC hexadecimaal, dus buiten het bereik dat grep zou verwachten voor utf8 (tot 0x7F). Controleer met printf ‘ a \ x7F ‘ | grep ‘ a ‘ zoals Ciro hierboven beschrijft.

Antwoord

Het bestand /etc/magic of /usr/share/misc/magic heeft een lijst met reeksen waarvan het commando file gebruikt om het bestandstype te bepalen.

Merk op dat binair bestand misschien wel een noodoplossing is. Soms worden bestanden met vreemde codering ook als binair beschouwd.

grep op Linux heeft enkele opties om binaire bestanden te verwerken, zoals --binary-files of -U / --binary

Reacties

Antwoord

Een van mijn studenten had dit probleem. Er zit een bug in grep in Cygwin. Als het bestand niet-Ascii-tekens heeft, zien grep en egrep het als binair.

Reacties

  • Dat klinkt als een functie, niet als een bug.Zeker gezien het feit dat er een opdrachtregeloptie is om het te besturen (-a / –text)

Answer

Beantwoord de vraag “Waarom beschouwt grep een bestand als binair?”, En gebruik iconv:

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

In mijn geval waren er Spaanse tekens die correct werden weergegeven in teksteditors, maar grep beschouwde ze als binair; iconv output wees me naar de regel- en kolomnummers van die karakters

In het geval van NUL karakters, iconv beschouwt ze als normaal en drukt dat soort uitvoer niet af, dus deze methode is niet geschikt

Antwoord

Ik had hetzelfde probleem. Ik heb vi -b [filename] gebruikt om de toegevoegde karakters te zien. Ik heb de besturingstekens ^@ en ^M gevonden. Typ vervolgens in vi :1,$s/^@//g om de ^@ -tekens te verwijderen. Herhaal deze opdracht voor ^M.

Waarschuwing: om de “blauwe” besturingstekens te krijgen, drukt u op Ctrl + v en vervolgens op Ctrl + M of Ctrl + @ . Sla vervolgens op en sluit vi af.

Answer

Ik had ook dit probleem, maar in mijn geval werd het veroorzaakt wanneer een overeenkomende regel is te lang.

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

grep zou het hele bestand goed doorlopen met veel patronen, maar wanneer een patroon overeenkwam met een ” zeer lange regel ” het stopte met Binary file myfile.txt matches.

Het toevoegen van -a lost ook dit probleem op, maar het pre-parseren van het bestand voor NULL of andere ongeldige karakters zou geen effect hebben (er zijn er geen anders zou grep niet compleet zijn voor andere patronen). In dit geval had de overtredende regel 25k + tekens!

Wat ik niet begrijp is waarom het alleen gebeurt wanneer grep de regel probeert terug te geven en niet wanneer deze is het aan het verwerken op zoek naar andere patronen.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *