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
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 jaNUL
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
, esimprintf "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ään0x7F
). 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
- Tarkemmin sanottuna koodausvirhe C99: n mukaisesti ’ s
mbrlen()
. Esimerkki ja lähteen tulkinta: unix.stackexchange.com/a/276028/32558
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.
--null-data
voivat olla hyödyllisiä, josNUL
on erotin.