Tein hyvin yksinkertaisen haun:

grep -R Milledgeville ~/Documents 

Ja jonkin ajan kuluttua tämä virhe ilmestyi:

grep: memory exhausted 

Kuinka voin välttää tämän?

Minulla on järjestelmässä 10 Gt RAM-muistia ja vähän sovelluksia juoksu, joten olen todella yllättynyt, että yksinkertaisella grepillä loppuu muisti. ~/Documents on noin 100 Gt ja sisältää kaikenlaisia tiedostoja.

grep -RI ei ehkä ole tätä ongelmaa, mutta haluan etsiä myös binaaritiedostoista.

Vastaa

Kaksi mahdollista ongelmaa:

  • grep -R (paitsi muokattu GNU grep, joka löytyy OS / X 10.8: sta ja uudemmista) seuraa symlinkkejä, vaikka vain ”” 100 gigatavua tiedostoja ~/Documents -palvelussa, esimerkiksi / -symbolilinkki saattaa silti olla, ja lopulta skannaat koko tiedostojärjestelmän, mukaan lukien tiedostot, kuten /dev/zero. Käytä grep -r uudemman GNU: n kanssa grep tai käytä vakiosyntaksia:

    find ~/Documents -type f -exec grep Milledgeville /dev/null {} + 

    (huomaa kuitenkin, että poistumistila ei kuvasta sitä, että kuvio on yhteensopiva vai ei).

  • grep etsii linjat, jotka vastaavat mallia. Tätä varten sen on ladattava yksi rivi kerrallaan muistiin. GNU grep toisin kuin monet muut grep -toteutuksilla ei ole rajoitusta lukemiesi rivien kokoon ja ne tukevat hakua binaaritiedostoista. Joten, jos sinulla on tiedosto, jolla on hyvin iso rivi (ts. Kaksi uutta rivimerkkiä on liian kaukana), suurempi kuin käytettävissä oleva muisti, se epäonnistuu.

    Se tapahtuisi tyypillisesti harva tiedosto. Voit kopioida sen:

    truncate -s200G some-file grep foo some-file 

    Sitä on vaikea kiertää. Voit tehdä sen (edelleen GNU: n kanssa grep):

    find ~/Documents -type f -exec sh -c "for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done" Milledgeville {} + 

    Tämä muuntaa NUL-merkkien jaksot yhdeksi uudeksi riviksi ennen syötteen syöttämistä grep. Se kattaisi tapaukset, joissa ongelma johtuu harvoista tiedostoista.

    Voit optimoida sen tekemällä sen vain suurille tiedostoille:

    find ~/Documents -type f \( -size -100M -exec \ grep -He Milledgeville {} + -o -exec sh -c "for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done" Milledgeville {} + \) 

    Jos tiedostot ovat eivät harvat ja sinulla on GNU-version versio grep ennen 2.6, voit käyttää --mmap -vaihtoehtoa. Rivit tallennetaan muistiin sen sijaan, että ne kopioitaisiin sinne, mikä tarkoittaa, että järjestelmä voi aina palauttaa muistiinpanon y hakemalla sivut tiedostoon. Tämä vaihtoehto poistettiin GNU: sta grep 2.6

Kommentit

  • @GodricSeer, se saattaa silti lukea suuren osan tiedostosta yhteen puskuriin, mutta jos se ei ole ’, etsi merkkijonoa sieltä ja ole ’ t ei löytänyt myöskään uuden rivin hahmoa, vetoni on, että se pitää kyseisen yhden puskurin muistissa ja lukee seuraavan puskurin sisään, koska sen on näytettävä se, jos osuma löytyy. Joten, ongelma on edelleen sama. Käytännössä 200 Gt: n harvan tiedoston grep epäonnistuu OOM: n kanssa.
  • @GodricSeer, no ei. Jos kaikki viivat ovat pieniä, grep voi hylätä tähän mennessä käsittelemänsä puskurit. Voit grep yes -lähdön loputtomiin käyttämättä enempää kuin muutama kilotavu muistia. Ongelma on rivien koko.
  • GNU grep --null-data -vaihtoehto voi olla hyödyllinen myös tässä. Se pakottaa NUL: n käytön uuden rivin sijasta tulolinjan päättäjänä.
  • @ 1_CR, hyvä asia, vaikka se asettaa myös lähtöjohdon päätteeksi NUL.
  • Voisiko fold -komentoapua näissä tilanteissa? Ajattele esimerkiksi dd if=/dev/sda | fold -b $((4096*1024*1024)) | grep -a "some string" , jos haluat rajoittaa tarvittavan muistin määrän 4 Gt: iin

Vastaa

En yleensä tee

find ~/Documents | xargs grep -ne "expression" 

Yritin joukkoa menetelmiä ja huomasin tämän olevan nopein. Huomaa, että tämä ei käsittele tiedostoja, joissa tiedoston nimi on välilyöntejä. Jos tiedät, että näin on ja sinulla on GNU-versio grepistä, voit käyttää:

find ~/Documents -print0 | xargs -0 grep -ne "expression" 

Jos et, voit käyttää:

 find ~/Documents -exec grep -ne "expression" "{}" \; 

Mikä exec grep jokaiselle tiedostolle.

Kommentit

  • Tämä rikkoo tiedostoja, joissa on välilyöntejä.
  • Hmm, totta.
  • Voit kiertää sen käyttämällä find -print0 | xargs -0 grep -ne 'expression'
  • @ChrisDown pikemminkin ei-suojattua ratkaisua kuin rikkoutuneita kannettavia ratkaisuja.
  • @ChrisDown Most suurimmat yksiköt ovat hyväksyneet find -print0 ja xargs -0 tähän mennessä: kaikki kolme BSD: tä, MINIX 3, Solaris 11,…

Vastaa

Voin ajatella muutamia tapoja kiertää tämä:

  • Sen sijaan kaikki tiedostot kerralla, tee yksi tiedosto kerrallaan.Esimerkki:

    find /Documents -type f -exec grep -H Milledgeville "{}" \; 
  • Jos sinun tarvitsee vain tietää, mitkä tiedostot sisältävät sanat, tee grep -l. Koska grep lopettaa etsinnän ensimmäisen osuman jälkeen, sen ei tarvitse jatkaa valtavien tiedostojen lukemista.

  • Jos haluat myös varsinaisen tekstin, voit merkitä kaksi erillinen greps pitkin:

    for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done 

kommentit

  • Viimeinen esimerkki ei kelpaa syntaksia – sinun ’ d on suoritettava komentokorvaus (ja sinun ei pitäisi tehdä sitä ’, koska grep tuottaa erottimen, joka on laillinen tiedostonimissä). Sinun on myös lainattava $file.
  • Jälkimmäinen esimerkki kärsii tiedostojen nimissä, joissa on rivinvaihto tai välilyönti, (se saa for käsittelemään tiedostoa kahtena argumenttina)
  • @DravSloan Muokkauksesi parannus, rikkoo edelleen laillisten tiedostojen nimiä.
  • Jätin sen sisään, koska se oli osa hänen vastaustaan, yritin vain parantaa sitä, jotta se toimisi (tapauksissa, joissa olen tiedostoissa ei ole välilyöntejä / uusia viivoja jne.).
  • Hänen – > hänen korjauksensa, anteeksi Jenny: /

Vastaa

Otin 6 Tt: n levyn etsimään kadonneita tietoja ja sain muistin loppuun -virheen. Tämän pitäisi toimia myös muissa tiedostoissa.

Ratkaisu, jonka keksimme, oli lukea levy paloina käyttämällä dd: tä ja tarttumalla paloihin. Tämä on koodi (big-grep.sh):

#problem: grep gives "memory exhausted" error on 6TB disks #solution: read it on parts if [ -z $2 ] || ! [ -e $1 ]; then echo "$0 file string|less -S # greps in chunks"; exit; fi FILE="$1" MATCH="$2" SIZE=`ls -l $1|cut -d\ -f5` CHUNKSIZE=$(( 1024 * 1024 * 1 )) CHUNKS=100 # greps in (100 + 1) x 1MB = 101MB chunks COUNT=$(( $SIZE / $CHUNKSIZE * CHUNKS )) for I in `seq 0 $COUNT`; do dd bs=$CHUNKSIZE skip=$(($I*$CHUNKS)) count=$(( $CHUNKS+1)) if=$FILE status=none|grep -UF -a --context 6 "$MATCH" done 

Kommentit

  • ellet lue päällekkäiset palat, saatat unohtaa ottelut palan rajoilla. Päällekkäisyyden on oltava vähintään yhtä suuri kuin merkkijono, jonka odotat vastaavan.
  • Päivitetty etsimään 1 Mt ylimääräistä kussakin 100 Mt: n kappaleessa … halpa hakkerointi

Vastaa

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