Jag har några databasdumpar från ett Windows-system i min låda. De är textfiler. Jag använder cygwin för att greppa igenom dem. Dessa verkar vara vanliga textfiler. Jag öppnar dem med textredigerare som anteckningsblock och wordpad och de ser läsbara ut. Men när jag kör grep på dem kommer det att sägas binary file foo.txt matches.

Jag har märkt att filerna innehåller några ascii NUL -tecken, vilket jag tror är artefakter från databasdumpen.

Så vad gör att grep anser att dessa filer är binära? NUL karaktär? Finns det en flagga i filsystemet? Vad behöver jag ändra för att få grep till visa mig raden matchar?

Kommentarer

  • --null-data kan vara användbart om NUL är avgränsaren.

Svar

Om det finns ett NUL karaktär var som helst i filen, grep kommer att betrakta det som en binär fil.

Det kan finnas en sådan lösning cat file | tr -d "\000" | yourgrep för att eliminera alla noll först, och sedan för att söka igenom filen.

Kommentarer

  • … eller använd -a / --text, åtminstone med GNU grep.
  • @derobert: faktiskt, på vissa (äldre) system ser grep rader, men dess utdata kommer att trunka varje matchande rad först NUL (antagligen därför att den kallar C ’ s printf och ger den den matchade raden?). På ett sådant system returnerar grep cmd .sh_history lika många tomma rader som det finns rader som matchar ’ cmd ’, eftersom varje rad i sh_history har ett specifikt format med en NUL i början av varje rad. (men din kommentar ” åtminstone på GNU grep ” sannolikt går i uppfyllelse. Jag don ’ t har en till hands just nu för att testa, men jag förväntar mig att de hanterar detta snyggt)
  • Är förekomsten av en NUL-karaktär det enda kriteriet? Jag tvivlar på det. Det ’ är förmodligen smartare än så. Allt som faller utanför Ascii 32-126-intervallet skulle vara min gissning, men vi ’ måste titta på källkoden för att vara säker.
  • Min info var från mansidan för den specifika grep-instansen. Din kommentar om implementeringen är giltig, källan trumlar docs.
  • Jag hade en fil som grep på cygwin ansågs vara binär eftersom den hade en lång streck (0x96) istället för en vanlig ASCII bindestreck / minus (0x2d). Jag antar att det här svaret löste problemet med OP ’, men det verkar som om det är ofullständigt.

Svar

grep -a fungerade för mig:

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

Kommentarer

  • Detta är det bästa, billigaste svaret IMO.
  • Men inte POSIX-kompatibelt
  • Har du något emot att förklara varför det inte är det? Det skulle vara bra att göra det tydligt för alla vi som hittar svaret som ett alternativ. Tack :).
  • Hej jag ’ har kommit hit en andra gång för att lära mig om denna LOL. En fransk accent (diakritisk) i texten orsakade att grep barf

Svar

Du kan använda strings verktyg för att extrahera textinnehållet från vilken fil som helst och sedan rör det genom grep, så här: strings file | grep pattern.

Kommentarer

  • Perfekt för att greppa loggfiler som kan vara delvis skadade
  • ja, ibland binär blandad loggning händer också. Det här är bra.

Svar

GNU grep 2.24 RTFS

Slutsats: Endast 2 och 2 fall:

  • NUL, t.ex. printf "a\0" | grep "a"

  • kodningsfel enligt C99 mbrlen(), t.ex.:

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

    eftersom \x80 inte kan vara den första byten i en UTF-8 Unicode-punkt: UTF-8 – Beskrivning | sv.wikipedia.org

Dessutom, som nämnts av Stéphane Chazelas Vad får grep att överväga en fil till vara binär? | Unix & Linux Stack Exchange , dessa kontroller görs endast upp till den första buffertavläsningen av längden TODO.

Endast upp till den första bufferten läs

Så om ett NUL- eller kodningsfel inträffar mitt i en mycket stor fil kan det gripas ändå.

Jag föreställer mig att det här är av prestationsskäl.

Till exempel: det här skriver ut linjen:

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

men detta gör det inte:

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

Den faktiska buffertstorleken beror på hur filen läses. T.ex.jämför:

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

Med sleep skickas den första raden till grep även om den bara är 1 byte lång eftersom processen går i viloläge och den andra läsningen kontrollerar inte om filen är binär.

RTFS

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

Hitta var stderr-felmeddelandet är kodat:

git grep "Binary file" 

Leder oss till /src/grep.c:

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

Om dessa variabler var väl namngivna, nådde vi i grunden slutsatsen.

kodningsfel_output

Snabb grepping för encoding_error_output visar att den enda kodvägen som kan ändra den går igenom buf_has_encoding_errors:

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

och sedan bara man mbrlen.

nlines_first_null och nlines

Initierat som:

intmax_t nlines_first_null = -1; nlines = 0; 

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

TODO när kan nlines_first_null < nlines någonsin vara falsk? Jag blev lat.

POSIX

Definierar inte binära alternativ grep – sök i en fil efter ett mönster | pubs.opengroup.org och GNU grep dokumenterar inte det, så RTFS är det enda sättet.

Kommentarer

  • Imponerande beskrivning !
  • Observera att kontrollen av giltig UTF-8 bara sker på UTF-8-platser. Observera också att kontrollen endast görs på den första bufferten som läses från filen som för en vanlig fil verkar vara 32768 byte på mitt system, men för ett rör eller uttag kan det vara så liten som en byte. Jämför till exempel (printf '\n\0y') | grep y med (printf '\n'; sleep 1; printf '\0y') | grep y.
  • @St é phaneChazelas ” Observera att kontrollen av giltig UTF-8 bara sker i UTF-8-lokaler ”: menar du om export LC_CTYPE='en_US.UTF-8' som i mitt exempel, eller något annat? Buf läste: fantastiskt exempel, lagt till svaret. Du har uppenbarligen läst källan mer än mig, påminner mig om de hackarkoans ” Studenten blev upplyst ” 🙂
  • Jag såg inte heller ’, men gjorde mycket nyligen
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 vilken version av GNU grep testade du mot?

Svar

En av mina textfiler sågs plötsligt som binär av grep:

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

Lösningen var att konvertera den med iconv:

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

Kommentarer

  • Detta hände mig också. I synnerhet var orsaken ett ISO-8859-1-kodat icke-brytande utrymme, som jag var tvungen att ersätta med ett vanligt utrymme för att få grep att söka i filen.
  • grep 2.21 behandlar ISO -8859 textfiler som om de är binära, lägg till export LC_ALL = C innan grep-kommandot.
  • @netawater Tack! Detta är t.ex. fallet om du har något som M ü ller i en textfil. Att ’ s 0xFC hexadecimal, så utanför intervallet grep skulle förvänta sig för utf8 (upp till 0x7F). Kontrollera med printf ’ a \ x7F ’ | grep ’ a ’ som Ciro beskriver ovan.

Svar

Filen /etc/magic eller /usr/share/misc/magic har en lista med sekvenser som kommandot file används för att bestämma filtypen.

Observera att binär kan bara vara en reservlösning. Ibland anses filer med konstig kodning också vara binära.

grep på Linux har några alternativ för att hantera binära filer som --binary-files eller -U / --binary

Kommentarer

Svar

En av mina elever hade det här problemet. Det finns ett fel i grep i Cygwin. Om filen inte har Ascii-tecken ser grep och egrep den som binär.

Kommentarer

  • Det låter som en funktion, inte ett fel.Speciellt med tanke på att det finns ett kommandoradsalternativ för att kontrollera det (-a / –text)

Svar

Svarar du faktiskt på frågan ”Vad gör att grep anser att en fil är binär?”, Kan du använda iconv:

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

I mitt fall fanns det spanska tecken som visade sig korrekt i textredigerare men grep betraktade dem som binära; iconv -utdata pekade på rad- och kolumnnumren för dessa tecken

I fallet med NUL tecken iconv anser att de är normala och kommer inte att skriva ut den typen av utdata så den här metoden är inte lämplig

Svar

Jag hade samma problem. Jag använde vi -b [filename] för att se de tillagda tecknen. Jag hittade kontrolltecknen ^@ och ^M. Skriv sedan :1,$s/^@//g för att ta bort ^@ -tecknen. Upprepa detta kommando för ^M.

Varning: För att få ”blå” kontrolltecken, tryck på Ctrl + v och sedan Ctrl + M eller Ctrl + @ . Spara och avsluta sedan vi.

Svar

Jag hade också det här problemet men i mitt fall orsakades det när en matchad linje är för länge.

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

grep skulle gå igenom hela filen bra med många mönster men när ett mönster matchade ett ” mycket lång rad ” den slutade med Binary file myfile.txt matches.

Att lägga till -a löser också detta problem, men att förbereda filen för NULL eller andra ogiltiga tecken kommer inte att ha någon effekt (det finns ingen annars grep skulle inte slutföra för andra mönster). I det här fallet hade den kränkande raden 25k + tecken!

Det jag inte förstår är varför det bara händer när grep försöker returnera raden och inte när den bearbetar den efter andra mönster.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *