Nagyon egyszerű keresést végeztem:
grep -R Milledgeville ~/Documents
És egy idő után ez a hiba megjelent:
grep: memory exhausted
Hogyan kerülhetem el ezt?
10 GB RAM van a rendszeremen és kevés alkalmazás van fut, ezért nagyon meglepődtem, hogy egy egyszerű grepnek elfogy a memóriája. A ~/Documents
kb. 100 GB, és mindenféle fájlt tartalmaz.
grep -RI
lehet, hogy nincs ez a probléma, de szeretném hogy bináris fájlokban is keressen.
Válasz
Két lehetséges probléma:
-
grep -R
(kivéve az OS / X 10.8 és újabb verzióin található módosított GNUgrep
elemeket) szimbolikus linkeket követ, tehát akkor is, ha csak “s” vannak 100 GB fájl a~/Documents
fájlban, előfordulhat, hogy még mindig van szimbolikus hivatkozás például a/
fájlra, és végül az egész fájlrendszert átvizsgálja fájlok, például/dev/zero
. Használja azgrep -r
alkalmazást egy újabb GNU-valgrep
, vagy használja a szokásos szintaxist:find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(azonban vegye figyelembe, hogy a kilépési állapot nem tükrözi azt a tényt, hogy a minta illeszkedik-e vagy sem).
-
grep
megtalálja a mintának megfelelő vonalakat. Ehhez egyszerre egy sort kell betölteni a memóriába. GNUgrep
sok más megvalósítások nem korlátozzák az olvasott sorok méretét, és támogatják a bináris fájlokban történő keresést. Tehát, ha van egy fájl, amelynek nagyon nagy sora van (vagyis két újsoros karakter nagyon messze van), nagyobb, mint a rendelkezésre álló memória, akkor meghiúsul.Ez általában egy ritka fájl. A következővel reprodukálhatja:
truncate -s200G some-file grep foo some-file
Ezt nehéz megkerülni. Megteheti úgy is (még mindig a GNU
grep
):find ~/Documents -type f -exec sh -c "for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done" Milledgeville {} +
Ez átalakítja a NUL karakterek sorozatát egy új sor karakterré, mielőtt a bemenetet
grep
. Ez azokra az esetekre vonatkozna, amikor a probléma ritka fájlok miatt következik be.Optimalizálhatná úgy, hogy csak nagy fájlok esetén teszi:
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 {} + \)
Ha a fájlok nem ritkák, és a GNU
grep
verziója van a , használhatja a--mmap
opciót. A sorok a memóriában lesznek leképezve, szemben az ott másolással, ami azt jelenti, hogy a rendszer mindig visszakaphatja a memóriát y az oldalak lapozásával a fájlba. Ezt a lehetőséget eltávolítottuk a GNUgrep
2.6
megjegyzésekből
Válasz
Általában megteszem
find ~/Documents | xargs grep -ne "expression"
Egy csomó módszert kipróbáltam, és ezt találtam a leggyorsabbnak. Ne feledje, hogy ez “nem kezeli nagyon jól a fájlnévvel szóközökkel rendelkező fájlokat. Ha tudja, hogy ez a helyzet, és van egy grn GNU verziója, használhatja:
find ~/Documents -print0 | xargs -0 grep -ne "expression"
Ha nem, akkor használhatja:
find ~/Documents -exec grep -ne "expression" "{}" \;
Amely exec
minden fájlhoz egy grepet fog adni.
Megjegyzések
- Ez megszakítja a szóközökkel rendelkező fájlokat.
- Hmm, ez igaz.
- Ezt megkerülheti a következővel:
find -print0 | xargs -0 grep -ne 'expression'
- @ChrisDown inkább nem védhető megoldás, mint törött hordozható megoldás.
- @ChrisDown Most a főbb egységek már elfogadták
find -print0
ésxargs -0
: mindhárom BSD, MINIX 3, Solaris 11,…
Válasz
Néhány módot tudok kitalálni:
-
Ehelyett az összes fájl egyszerre történő megcsipegetésével, egyszerre csak egy fájlt végezzen.Példa:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
-
Ha csak tudnia kell, hogy mely fájlok tartalmazzák a szavakat, akkor tegye a következőt:
grep -l
helyett. Mivel a grep az első találat után abbahagyja a keresést, nem kell folytatnia a hatalmas fájlok olvasását. -
Ha a tényleges szöveget is szeretné, akkor kettőt sztringelhet külön grepek:
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
Megjegyzések
- Az utolsó példa érvénytelen szintaxis – ‘ parancscserét kell végrehajtania (és ezt nem kell megtennie,
= “cc67858b36”> a fájlnevekben törvényes elválasztó segítségével kimeneti). Idéznie kell a$file
-t is.
for
fájlt két argumentumként fogja feldolgozni) Válasz
6 TB-os lemezt vettem az elveszett adatok keresésére, és a memória kimerült -hiba. Ennek más fájloknál is működnie kell.
A megoldás, amellyel előálltunk, az volt, hogy a lemezt darabokban olvastuk el a dd használatával, és megcsipkedtük a darabokat. Ez a kód (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
Megjegyzések
- Hacsak nem olvasol átfedő darabok, valószínűleg hiányoznának a meccsek a darabok határán. Az átfedésnek legalább akkorának kell lennie, mint az a karakterlánc, amelyre számítania szeretne.
- Frissítve 1 MB-os extra keresésre minden 100 MB-os darabban … olcsó hack
grep
eldobhatja az eddig feldolgozott puffereket.grep
ayes
kimenetét korlátlanul megadhatja néhány kilobájtnál több memória felhasználása nélkül. A probléma a sorok mérete.--null-data
opció itt is hasznos lehet. Kényszeríti a NUL használatát az újsor helyett bemeneti vonal terminátorként.dd if=/dev/sda | fold -b $((4096*1024*1024)) | grep -a "some string"
lehetőségre, hogy a szükséges memória mennyiségét 4 GB-ra korlátozza.