Jeg har noen databasedumpinger fra et Windows-system i boksen min. De er tekstfiler. Jeg bruker cygwin til å grep gjennom dem. Dette ser ut til å være vanlige tekstfiler. Jeg åpner dem med tekstredigerere som notisblokk og wordpad, og de ser lesbare ut. Når jeg kjører grep på dem, vil det si binary file foo.txt matches.

Jeg har lagt merke til at filene inneholder noen ascii NUL tegn, som jeg mener er gjenstander fra databasedumpen.

Så hva får grep til å betrakte disse filene som binære? NUL -tegnet? Er det et flagg på filsystemet? Hva må jeg endre for å få grep til vise meg linjekampene?

Kommentarer

  • --null-data kan være nyttig hvis NUL er avgrenseren.

Svar

Hvis det er NUL tegn hvor som helst i filen, grep vil betrakte det som en binær fil.

Det kan være en løsning som denne cat file | tr -d "\000" | yourgrep for å eliminere alle null først, og deretter for å søke gjennom filen.

Kommentarer

  • … eller bruk -a / --text, i det minste med GNU grep.
  • @derobert: faktisk, på noen (eldre) systemer, ser grep linjer, men utgangen vil avkutte hver samsvarende linje i første omgang NUL (sannsynligvis fordi den kaller C ‘ s printf og gir den samsvarende linje?). På et slikt system vil grep cmd .sh_history returnere så mange tomme linjer som det er linjer som samsvarer med ‘ cmd ‘, ettersom hver linje i sh_history har et bestemt format med en NUL i begynnelsen av hver linje. (men kommentaren din » i det minste på GNU grep » blir sannsynligvis oppfylt. Jeg don ‘ har ikke en til stede akkurat nå for å teste, men jeg forventer at de takler dette pent)
  • Er tilstedeværelsen av et NUL-tegn det eneste kriteriet? Det tviler jeg på. Det ‘ er sannsynligvis smartere enn det. Alt som faller utenfor Ascii 32-126-serien vil være mitt gjetning, men vi ‘ vi må se på kildekoden for å være sikker.
  • Min informasjon var fra mannssiden til den spesifikke grep-forekomsten. Kommentaren din om implementering er gyldig, kilde trumfer docs.
  • Jeg hadde en fil som grep på cygwin betraktet som binær fordi den hadde en lang bindestrek (0x96) i stedet for en vanlig ASCII bindestrek / minus (0x2d). Jeg antar at dette svaret løste OP ‘ s problem, men det ser ut til at det er ufullstendig.

Svar

grep -a fungerte for meg:

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

Kommentarer

  • Dette er det beste, minst kostbare svaret IMO.
  • Men ikke POSIX-kompatibelt
  • Har du noe imot å forklare hvorfor det ikke er det? Det ville være bra å gjøre det klart, for alle oss som finner dette svaret som et alternativ. Takk :).
  • Hei, jeg ‘ har kommet hit andre gang for å lære denne LOL på nytt. En fransk aksent (diakritisk) i teksten førte til at grep barf

Svar

Du kan bruke strings verktøy for å trekke ut tekstinnholdet fra hvilken som helst fil og deretter pipe det gjennom grep, slik: strings file | grep pattern.

Kommentarer

  • Ideell for å gripe loggfiler som kan være delvis ødelagt
  • ja, noen ganger binær blandet logging skjer også. Dette er bra.

Svar

GNU grep 2.24 RTFS

Konklusjon: Bare 2 og 2 tilfeller:

  • NUL, f.eks printf "a\0" | grep "a"

  • kodingsfeil i henhold til C99 mbrlen(), f.eks:

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

    fordi \x80 ikke kan være den første byten i et UTF-8 Unicode-punkt: UTF-8 – Beskrivelse | no.wikipedia.org

Videre, som nevnt av Stéphane Chazelas Hva får grep til å vurdere en fil til være binær? | Unix & Linux Stack Exchange , disse kontrollene gjøres bare opp til den første bufferavlesningen av lengden TODO.

Bare opp til den første bufferen les

Så hvis det oppstår en NUL- eller kodingsfeil midt i en veldig stor fil, kan det bli grepet uansett.

Jeg forestiller meg at dette er av ytelsesmessige grunner.

F.eks: dette skriver ut linjen:

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

men dette gjør ikke det:

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

Den faktiske bufferstørrelsen avhenger av hvordan filen leses. F.eks.sammenlign:

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

Med sleep blir den første linjen sendt til grep selv om den bare er 1 byte lenge fordi prosessen går i dvale, og den andre lesingen ikke sjekker om filen er binær.

RTFS

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

Finn hvor stderr-feilmeldingen er kodet:

git grep "Binary file" 

Leder oss til /src/grep.c:

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

Hvis disse variablene ble godt kalt, nådde vi i utgangspunktet konklusjonen.

coding_error_output

Rask grepping for encoding_error_output viser at den eneste kodebanen som kan endre den går gjennom buf_has_encoding_errors:

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

så bare man mbrlen.

nlines_first_null og nlines

Initialisert som:

intmax_t nlines_first_null = -1; nlines = 0; 

så når en null blir funnet 0 <= nlines_first_null blir sant.

TODO når kan nlines_first_null < nlines noen gang være falsk? Jeg ble lat.

POSIX

Definerer ikke binære opsjoner grep – søk i en fil etter et mønster | pubs.opengroup.org , og GNU grep dokumenterer det ikke, så RTFS er den eneste måten.

Kommentarer

  • Imponerende forklaring !
  • Merk at sjekken for gyldig UTF-8 bare skjer på UTF-8-steder. Vær også oppmerksom på at sjekken bare gjøres på den første bufferen som leses fra filen, som for en vanlig fil ser ut til å være 32768 byte på systemet mitt, men for et rør eller en stikkontakt kan den være så liten som en byte. Sammenlign for eksempel (printf '\n\0y') | grep y med (printf '\n'; sleep 1; printf '\0y') | grep y.
  • @St é phaneChazelas » Merk at sjekken for gyldig UTF-8 bare skjer i UTF-8-lokaler «: mener du om export LC_CTYPE='en_US.UTF-8' som i mitt eksempel, eller noe annet? Buf leste: fantastisk eksempel, lagt til svaret. Du har tydeligvis lest kilden mer enn meg, minner meg om de hacker koans » Studenten ble opplyst » 🙂
  • Jeg så ikke ‘ heller ikke i detalj, men gjorde veldig nylig
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 hvilken versjon av GNU grep testet du mot?

Svar

En av tekstfilene mine ble plutselig sett på som binær av grep:

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

Løsningen var å konvertere den ved å bruke iconv:

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

Kommentarer

  • Dette skjedde med meg også. Spesielt var årsaken et ISO-8859-1-kodet ikke-brytende rom, som jeg måtte erstatte med et vanlig mellomrom for å få grep til å søke i filen.
  • grep 2.21 behandler ISO -8859 tekstfiler som om de er binære, legg til eksport LC_ALL = C før grep-kommando.
  • @netawater Takk! Dette er f.eks. saken hvis du har noe sånt som M ü ller i en tekstfil. At ‘ s 0xFC heksadesimal, så utenfor området grep forventer for utf8 (opp til 0x7F). Sjekk med printf ‘ a \ x7F ‘ | grep ‘ a ‘ som Ciro beskriver ovenfor.

Svar

Filen /etc/magic eller /usr/share/misc/magic har en liste over sekvenser som kommandoen file bruker for å bestemme filtypen.

Merk at binær bare kan være en reserveløsning. Noen ganger blir filer med merkelig koding også betraktet som binære.

grep på Linux har noen muligheter for å håndtere binære filer som --binary-files eller -U / --binary

Kommentarer

Svar

En av elevene mine hadde dette problemet. Det er en feil i grep i Cygwin. Hvis filen ikke har Ascii-tegn, ser grep og egrep den som binær.

Kommentarer

  • Det høres ut som en funksjon, ikke en feil.Spesielt gitt er det et kommandolinjealternativ for å kontrollere det (-a / –text)

Svar

Svar på spørsmålet «Hva får grep til å betrakte en fil som binær?», Kan du bruke iconv:

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

I mitt tilfelle var det spanske tegn som dukket opp riktig i tekstredigerere, men grep betraktet dem som binære; iconv utgang pekte meg på linje- og kolonnetallene til disse tegnene

I tilfelle NUL tegn, iconv vil betrakte dem som normale og vil ikke skrive ut den typen utdata, så denne metoden er ikke egnet

Svar

Jeg hadde det samme problemet. Jeg brukte vi -b [filename] for å se de tegnene som ble lagt til. Jeg fant kontrolltegnene ^@ og ^M. Deretter skriver vi inn :1,$s/^@//g for å fjerne ^@ tegnene. Gjenta denne kommandoen for ^M.

Advarsel: For å få de «blå» kontrolltegnene, trykk Ctrl + v og deretter Ctrl + M eller Ctrl + @ . Lagre og avslutt vi.

Svar

Jeg hadde også dette problemet, men i mitt tilfelle ble det forårsaket når en samsvarende linje er for lenge.

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

grep vil løpe gjennom hele filen fint med mange mønstre, men når et mønster matchet et » veldig lang linje » den stoppet med Binary file myfile.txt matches.

Hvis du legger til -a, løses også dette problemet, men forhåndsparsering av filen for NULL eller andre ugyldige tegn vil ikke ha noen effekt (det er ingen ellers vil grep ikke fullføre for andre mønstre). I dette tilfellet hadde den fornærmende linjen 25k + tegn!

Det jeg ikke forstår er hvorfor det bare skjer når grep prøver å returnere linjen og ikke når den behandler den på jakt etter andre mønstre.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *