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
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 vilgrep 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 enNUL
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.eksprintf "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 til0x7F
). 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
- Mer presist, kodingsfeil i henhold til C99 ‘ s
mbrlen()
. Eksempel og kildetolkning på: unix.stackexchange.com/a/276028/32558
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.
--null-data
kan være nyttig hvisNUL
er avgrenseren.