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 GNUgrep
, 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 kanssagrep
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. GNUgrep
toisin kuin monet muutgrep
-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
ennen2.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: stagrep
2.6
Kommentit
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
jaxargs -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
grep
voi hylätä tähän mennessä käsittelemänsä puskurit. Voitgrep
yes
-lähdön loputtomiin käyttämättä enempää kuin muutama kilotavu muistia. Ongelma on rivien koko.--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ä.dd if=/dev/sda | fold -b $((4096*1024*1024)) | grep -a "some string"
, jos haluat rajoittaa tarvittavan muistin määrän 4 Gt: iin