Jeg har nogle databasedumps fra et Windows-system på min boks. De er tekstfiler. Jeg bruger cygwin til at gribe igennem dem. Disse ser ud til at være almindelige tekstfiler. Jeg åbner dem med teksteditorer som notesblok og wordpad, og de ser læsbare ud. Når jeg kører grep på dem, vil det sige binary file foo.txt matches.

Jeg har bemærket, at filerne indeholder nogle ascii NUL tegn, som jeg mener er artefakter fra databasedumpen.

Så hvad får grep til at betragte disse filer som binære? NUL tegnet? Er der et flag på filsystemet? Hvad skal jeg ændre for at få grep til vise mig linjen matcher?

Kommentarer

  • --null-data kan være nyttige, hvis NUL er afgrænseren.

Svar

Hvis der er et NUL tegn hvor som helst i filen, grep betragter det som en binær fil.

Der kan muligvis være en løsning som denne cat file | tr -d "\000" | yourgrep for at fjerne alle nul først, og derefter for at søge i filen.

Kommentarer

  • … eller brug -a / --text, i det mindste med GNU grep.
  • @derobert: faktisk, på nogle (ældre) systemer, ser grep linjer, men dens output vil afkorte hver matchende linje ved første NUL (sandsynligvis fordi det kalder C ‘ s printf og giver det den matchede linje?). På et sådant system returnerer grep cmd .sh_history så mange tomme linjer, som der er linjer, der matcher ‘ cmd ‘, da hver linje i sh_history har et specifikt format med en NUL i begyndelsen af hver linje. (men din kommentar ” i det mindste på GNU grep ” går sandsynligvis i opfyldelse. Jeg don ‘ har ikke en ved hånden lige nu for at teste, men jeg forventer, at de håndterer dette pænt)
  • Er tilstedeværelsen af et NUL-tegn det eneste kriterium? Det tvivler jeg på. Det ‘ er sandsynligvis klogere end det. Alt, hvad der falder uden for Ascii 32-126-området, ville være mit gæt, men vi ‘ skulle se på kildekoden for at være sikker.
  • Min info var fra mandsiden for den specifikke grep-forekomst. Din kommentar til implementering er gyldig, kilde trumfer docs.
  • Jeg havde en fil, som grep på cygwin betragtes som binær, fordi den havde et langt bindestreg (0x96) i stedet for en almindelig ASCII-bindestreg / minus (0x2d). Jeg antager, at dette svar løste OP ‘ s-problemet, men det ser ud til, at det er ufuldstændigt.

Svar

grep -a fungerede for mig:

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

Kommentarer

  • Dette er det bedste, billigste svar IMO.
  • Men ikke POSIX-kompatibelt
  • Har du noget imod at forklare, hvorfor det ikke er? Det ville være godt at gøre det klart for os alle, der finder dette svar som en mulighed. Tak :).
  • Hej jeg ‘ er kommet her anden gang for at genlære denne LOL. En fransk accent (diakritisk) i teksten fik grep til at barf

Svar

Du kan bruge strings hjælpeprogram til at udtrække tekstindholdet fra enhver fil og derefter pibe det gennem grep på denne måde: strings file | grep pattern.

Kommentarer

  • Ideel til at gribe logfiler, der muligvis er delvis beskadiget
  • ja, undertiden binær blandet logning sker også. Dette er godt.

Svar

GNU grep 2.24 RTFS

Konklusion: Kun 2 og 2 tilfælde:

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

  • kodningsfejl ifølge 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 byte i et UTF-8 Unicode-punkt: UTF-8 – Beskrivelse | da.wikipedia.org

Desuden, som nævnt af Stéphane Chazelas Hvad får grep til at overveje en fil til være binær? | Unix & Linux Stack Exchange , disse kontroller udføres kun op til den første bufferlæsning af længden TODO.

Læs kun op til den første buffer

Så hvis der opstår en NUL- eller kodningsfejl midt i en meget stor fil, kan det gribes alligevel.

Jeg forestiller mig, at dette er af ydeevneårsager.

F.eks .: dette udskriver linjen:

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

men dette gør det ikke:

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

Den faktiske bufferstørrelse afhænger af, hvordan filen læses. For eksempel.sammenlign:

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

Med sleep bliver den første linje sendt til grep, selvom den kun er 1 byte lang, fordi processen går i dvale, og den anden læsning kontrollerer ikke, om filen er binær.

RTFS

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

Find, hvor stderr-fejlmeddelelsen er kodet:

git grep "Binary file" 

Fører os 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 variabler blev godt navngivet, nåede vi dybest set til konklusionen.

kodning_fejl_output

Hurtig grepping til encoding_error_output viser, at den eneste kodesti, der kan ændre den, går gennem 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

Initialiseret som:

intmax_t nlines_first_null = -1; nlines = 0; 

så når en null er fundet 0 <= nlines_first_null bliver sand.

TODO hvornår kan nlines_first_null < nlines nogensinde være falske? Jeg blev doven.

POSIX

Definerer ikke binære indstillinger grep – søg i en fil efter et mønster | pubs.opengroup.org , og GNU grep dokumenterer det ikke, så RTFS er den eneste måde.

Kommentarer

  • Imponerende forklaring !
  • Bemærk, at kontrollen for gyldig UTF-8 kun sker i UTF-8-lokaliteter. Bemærk også, at kontrollen kun udføres på den første buffer, der læses fra filen, som for en almindelig fil synes at være 32768 byte på mit system, men for et rør eller et stik kan være så lille som en byte. Sammenlign f.eks. (printf '\n\0y') | grep y med (printf '\n'; sleep 1; printf '\0y') | grep y.
  • @St é phaneChazelas ” Bemærk, at kontrollen for gyldig UTF-8 kun sker i UTF-8-lokaliteter “: mener du om export LC_CTYPE='en_US.UTF-8' som i mit eksempel, eller noget andet? Buf læst: fantastisk eksempel, tilføjet til svar. Du har tydeligvis læst kilden mere end mig, minder mig om de hacker koans ” Studenten blev oplyst ” 🙂
  • Jeg kiggede heller ikke ‘, men gjorde for nylig
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 hvilken version af GNU grep testede du mod?

Svar

En af mine tekstfiler blev pludselig set som binær af grep:

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

Løsningen var at konvertere den ved hjælp af iconv:

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

Kommentarer

  • Dette skete også med mig. Især var årsagen et ISO-8859-1-kodet ikke-brudende rum, som jeg måtte erstatte med et almindeligt mellemrum for at få grep til at søge i filen.
  • grep 2.21 behandler ISO -8859 tekstfiler, som om de er binære, tilføj eksport LC_ALL = C før grep-kommando.
  • @netawater Tak! Dette er f.eks. tilfældet, hvis du har noget som M ü ller i en tekstfil. At ‘ s 0xFC hexadecimal, så uden for området grep ville forvente for utf8 (op til 0x7F). Tjek 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 bruges til at bestemme filtypen.

Bemærk at binær måske bare er en alternativ løsning. Nogle gange betragtes filer med mærkelig kodning også som binære.

grep på Linux har nogle muligheder for at håndtere binære filer som --binary-files eller -U / --binary

Kommentarer

Svar

En af mine elever havde dette problem. Der er en fejl i grep i Cygwin. Hvis filen ikke har Ascii-tegn, ser grep og egrep den som binær.

Kommentarer

  • Det lyder som en funktion, ikke en fejl.Især givet er der en kommandolinjemulighed til at kontrollere den (-a / –text)

Svar

Faktisk besvare spørgsmålet “Hvad får grep til at betragte en fil som binær?”, Kan du bruge iconv:

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

I mit tilfælde var der spanske tegn, der viste sig korrekt i teksteditorer, men grep betragtede dem som binære; iconv output pegede på linje- og søjlenumrene for disse tegn

I tilfælde af NUL tegn iconv betragter dem som normale og vil ikke udskrive den slags output, så denne metode er ikke egnet

Svar

Jeg havde det samme problem. Jeg brugte vi -b [filename] til at se de tilføjede tegn. Jeg fandt kontroltegnene ^@ og ^M. Derefter skriver vi :1,$s/^@//g for at fjerne ^@ tegn. Gentag denne kommando for ^M.

Advarsel: For at få de “blå” kontroltegn skal du trykke på Ctrl + v og derefter Ctrl + M eller Ctrl + @ . Gem derefter og afslut vi.

Svar

Jeg havde også dette problem, men i mit tilfælde skyldtes det, når en matchet linje er for længe.

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

grep ville løbe igennem hele filen fint med mange mønstre, men når et mønster matchede et ” meget lang linje ” den stoppede med Binary file myfile.txt matches.

Tilføjelse af -a løser også dette problem, men præ-parsing af filen til NULL eller andre ugyldige tegn ville ikke have nogen virkning (der er ingen, ellers ville grep ikke udfylde for andre mønstre). I dette tilfælde havde den fornærmende linje 25k + tegn!

Det jeg ikke forstår er hvorfor det kun sker, når grep forsøger at returnere linjen og ikke når den behandler det på udkig efter andre mønstre.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *