Minun laatikossa on joitain Windows-järjestelmän tietokannan kaatopaikkoja. Ne ovat tekstitiedostoja. Käytän cygwiniä niiden läpi hakemiseen. Nämä näyttävät olevan tavallisia tekstitiedostoja; avaan ne tekstieditorilla, kuten muistilehtiöllä ja wordpadilla, ja ne näyttävät luettavilta. Kun kuitenkin suoritan grepin niille, sanotaan binary file foo.txt matches.

Olen huomannut, että tiedostot sisältävät joitain ascii NUL -merkkejä, jotka uskon olevan tietokannan dumpin artefakteja.

Mikä siis saa grepin pitämään näitä tiedostoja binäärinä? NUL -merkki? Onko tiedostojärjestelmässä lippua? Mitä minun on vaihdettava, jotta grep näytetäänkö viivavastaavuudet?

Kommentit

  • --null-data voivat olla hyödyllisiä, jos NUL on erotin.

Vastaa

Jos NUL -merkki missä tahansa tiedoston kohdassa, grep pitää sitä binaaritiedostona.

Tämän kaltainen kiertotapa voi olla cat file | tr -d "\000" | yourgrep poistamiseksi kaikki tyhjä ensin, ja sitten hakea tiedoston kautta.

Kommentit

  • … tai käytä -a / --text, ainakin GNU-grepillä.
  • @derobert: joissakin (vanhemmissa) järjestelmissä grep katso rivejä, mutta sen tulos katkaisee kunkin vastaavan rivin ensimmäisessä NUL (todennäköisesti johtuu siitä, että se kutsuu C ’ s printf: tä ja antaa sille sopivan rivin?). Tällaisessa järjestelmässä grep cmd .sh_history palauttaa niin monta tyhjää riviä kuin riviä, jotka vastaavat ’ cmd ’, koska jokaisella sh_history-rivillä on oma muoto ja NUL kunkin rivin alussa. (mutta kommenttisi ” ainakin GNU: n grep ” -sivustolla todennäköisesti toteutuu. En ’ T: llä ei ole tällä hetkellä testattavaa, mutta uskon, että he käsittelevät tämän hyvin)
  • Onko NUL-merkin läsnäolo ainoa kriteeri? Epäilen sitä. Se ’ on todennäköisesti sitä älykkäämpi. Kaikki Ascii 32-126 -alueen ulkopuolelle jäävä arvaus, mutta ’ meidän on tarkasteltava lähdekoodia varmistaaksemme.
  • Tietoni olivat tietyn grep-instanssin man-sivulta. Kommenttisi toteutuksesta on kelvollinen, lähde kumoaa asiakirjat.
  • Minulla oli tiedosto, joka grep cygwinissä katsottiin binaariseksi, koska sillä oli pitkä viiva (0x96) eikä tavallinen ASCII-väliviiva / miinus (0x2d). Luulen, että tämä vastaus ratkaisi OP ’ -ongelman, mutta näyttää siltä, että se on puutteellinen.

Vastaa

grep -a toimi minulle:

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

kommentit

  • Tämä on paras, halvin vastaus IMO.
  • Mutta ei POSIX-yhteensopiva
  • Haluatko selittää miksi se ei ole? Olisi hyvä tehdä se selväksi kaikille meille, jotka pidämme tätä vastausta vaihtoehtona. Kiitos :).
  • Hei, olen ’ tullut tänne TOISEN kerran oppimaan tämän LOL: n uudelleen. Ranskalainen aksentti (diakriittinen) tekstissä aiheutti grepin palkeuden.

Vastaa

Voit käyttää strings -apuohjelma poimia tekstisisältö mistä tahansa tiedostosta ja viedä se sitten läpi grep, kuten tämä: strings file | grep pattern.

kommentit

  • ihanteellinen osittain vioittuneiden lokitiedostojen hakemiseen
  • kyllä, joskus binäärinen sekaloki myös tapahtuu. Tämä on hyvä.

Vastaa

GNU grep 2.24 RTFS

Johtopäätös: vain 2 ja 2 tapausta:

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

  • koodausvirhe C99: n mukaisesti mbrlen(), esim .:

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

    koska \x80 ei voi olla UTF-8 Unicode-pisteen ensimmäinen tavu: UTF-8 – kuvaus | fi.wikipedia.org

Lisäksi, kuten Stéphane Chazelas mainitsi Mikä saa grepin pitämään tiedostoa olla binaarinen? | Unix & Linux Stack Exchange , nämä tarkistukset tehdään vain ensimmäiseen TODO-pituisen puskurilukuun asti.

Vain ensimmäiseen puskuriin asti lukee

Joten jos NUL- tai koodausvirhe tapahtuu erittäin suuren tiedoston keskellä, se saattaa olla joka tapauksessa greppattu.

Luulen, että tämä johtuu suorituskyvyn syistä.

Esimerkki: tämä tulostaa rivin:

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

mutta näin ei ole:

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

Puskurin todellinen koko riippuu tiedoston lukemisesta. Esimerkiksi.vertaa:

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

sleep -toiminnon avulla ensimmäinen rivi siirtyy grepiin, vaikka se olisi vain 1 tavu pitkä, koska prosessi menee lepotilaan, eikä toinen luettu tarkista, onko tiedosto binaarinen.

RTFS

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

Etsi, missä stderr-virheilmoitus on koodattu:

git grep "Binary file" 

Johtaa meidät /src/grep.c:

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

Jos nämä muuttujat nimettiin hyvin, päädyimme periaatteeseen.

encoding_error_output

Nopea tarkistus encoding_error_output osoittaa, että ainoa koodipolku, joka voi muokata sitä, kulkee buf_has_encoding_errors:

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

sitten vain man mbrlen.

nlines_first_null ja nlines

Alustettu nimellä:

intmax_t nlines_first_null = -1; nlines = 0; 

joten kun nolla löydetään, 0 <= nlines_first_null tulee totta.

TODO milloin nlines_first_null < nlines ole koskaan väärä? Sain laiskan.

POSIX

Ei määritä binaariasetuksia grep – etsi tiedosto tiedostosta | pubs.opengroup.org , ja GNU grep ei dokumentoi sitä, joten RTFS on ainoa tapa.

Kommentit

  • Vaikuttava selitys !
  • Huomaa, että kelvollisen UTF-8: n tarkistus tapahtuu vain UTF-8-alueilla. Huomaa myös, että tarkistus tehdään vain ensimmäisestä tiedostosta luetusta puskurista, joka tavalliselle tiedostolle näyttää olevan 32768 tavua järjestelmässäni, mutta putki tai pistorasia voi olla yhtä pieni kuin yksi tavu. Vertaa (printf '\n\0y') | grep y esimerkiksi (printf '\n'; sleep 1; printf '\0y') | grep y -sarjaan.
  • @St é phaneChazelas ” Huomaa, että kelvollisen UTF-8: n tarkistus tapahtuu vain UTF-8-alueilla ”: tarkoitatko export LC_CTYPE='en_US.UTF-8' kuten esimerkissäni, tai jotain muuta? Buf read: hämmästyttävä esimerkki, lisätty vastaukseen Olet selvästi lukenut lähdettä enemmän kuin minä, muistuttaa minua niistä hakkereiden koaaneista ” Opiskelija valaistui ” 🙂
  • En katsonut ’ myöskään yksityiskohtia, mutta teki äskettäin
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 mitä GNU grep -versiota testasit?

Vastaus

Grep piti yhtäkkiä yhtä tekstitiedostoistani binäärisenä:

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

Ratkaisu oli muuntaa se käyttämällä iconv:

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

kommentteja

  • Tämä tapahtui myös minulle. Erityisesti syy oli ISO-8859-1-koodattu murtumaton tila, joka minun täytyi korvata tavallisella välilyönnillä saadakseni grep-hakuja tiedostosta.
  • grep 2.21 käsittelee ISO-tiedostoa -8859 tekstitiedostoa kuin ne olisivat binaarisia, lisää vienti LC_ALL = C ennen grep-komentoa.
  • @netawater Kiitos! Tämä on esim. tapaus, jos tekstitiedostossa on jotain M ü ller. Että ’ s 0xFC heksadesimaali, joten alueen ulkopuolella grep odottaisi utf8: lle (enintään 0x7F). Tarkista printf ’ a \ x7F ’ | grep ’ a ’ kuten Ciro kuvailee yllä.

Vastaa

Tiedostossa /etc/magic tai /usr/share/misc/magic on luettelo sekvensseistä, jotka komennolla file käyttää tiedostotyypin määrittämiseen.

Huomaa , että binaarinen voi olla vain vararatkaisu. Joskus tiedostoja, joilla on outo koodaus, pidetään myös binaarisina.

grep Linuxissa on joitain vaihtoehtoja binaaritiedostojen käsittelemiseksi, kuten --binary-files tai -U / --binary

kommentit

vastaus

Yhdellä oppilaistani oli tämä ongelma. grep -kohdassa on vika: Cygwin. Jos tiedostossa on muita kuin Ascii-merkkejä, grep ja egrep näkevät sen binaarisena.

Kommentit

  • Se kuulostaa ominaisuudelta, ei virheltä.Erityisesti siinä on komentorivivaihtoehto sen hallitsemiseksi (-a / –text)

Answer

Oikeastaan vastaamalla kysymykseen ”Mikä saa grepin pitämään tiedostoa binäärisenä?”, Voit käyttää iconv:

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

Minun tapauksessani oli espanjalaisia merkkejä, jotka näkyivät oikein tekstieditorissa, mutta grep piti niitä binäärinä; iconv -lähtö osoitti minut näiden merkkien rivi- ja sarakenumeroihin.

NUL -merkkien tapauksessa iconv pitää heitä normaaleina eikä tulosta tällaista tulosta, joten tämä menetelmä ei sovi

Vastaa

Minulla oli sama ongelma. Käytin vi -b [filename] nähdäksesi lisätyt merkit. Löysin ohjausmerkit ^@ ja ^M. Kirjoita sitten vi-muodossa :1,$s/^@//g poistaaksesi ^@ -merkit. Toista tämä komento kohdalle ^M.

Varoitus: Saadaksesi siniset ohjausmerkit, paina Ctrl + v ja sitten Ctrl + M tai Ctrl + @ . Tallenna ja poistu sitten vi.

Vastaa

Minulla oli myös tämä ongelma, mutta minun tapauksessani se aiheutui, kun vastaava viiva on liian pitkä.

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

grep juoksisi koko tiedoston läpi hyvin monilla kuvioilla, mutta kun kuvio vastasi ” erittäin pitkä rivi ” se pysähtyi Binary file myfile.txt matches.

-a -kuvakkeen lisääminen ratkaisee myös tämän ongelman, mutta NULL-tiedostoa tai muita virheellisiä merkkejä koskevan tiedoston esikäsittelyllä ei olisi vaikutusta (muita ei ole, jos grep ei täydennä muita malleja). Tällöin rikkoneella rivillä oli 25k + merkkiä!

En ymmärrä, miksi se tapahtuu vain, kun grep yrittää palauttaa rivin, ei kun se käsittelee sitä etsimällä muita malleja.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *