私は非常に簡単な検索をしています。
grep -R Milledgeville ~/Documents
しばらくすると、次のエラーが表示されました。
grep: memory exhausted
これをどのように避けることができますか?
私のシステムには10GBのRAMがあり、実行中のアプリケーションがほとんどないため、単純なgrepでもメモリが不足する可能性があることに本当に驚きました。~/Documents
約100GB、さまざまなファイルが含まれています。
grep -RI
この問題はないかもしれませんが、バイナリファイルでも検索したいと思います。
答え1
2つの潜在的な問題:
grep -R
(OS / X 10.8以降で見つかった修正されたGNUを除くgrep
)シンボリックリンクに従ってください。したがって、100 GBのファイルしか存在しない場合でも、~/Documents
シンボリックリンクが残っている可能性があります/
。たとえば、ファイルシステム全体を検索します。 ./dev/zero
最新のgrep -r
GNUと組み合わせて使用するgrep
か、標準構文を使用するには:find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(ただし、終了状態はパターンが一致したかどうかを反映しないことに注意してください。)
grep
パターンに一致する線を探します。これを行うには、メモリに一度に1行ずつロードする必要があります。grep
他の多くの実装とは異なり、GNUはgrep
読み取る行のサイズに制限はなく、バイナリファイル内の検索をサポートしています。そのため、ファイルに使用可能なメモリよりも大きな非常に大きな行(2行改行など)があると失敗します。これは通常スパースファイルで発生します。次のコマンドを使用して再現できます。
truncate -s200G some-file grep foo some-file
この問題は解決するのが難しいです。次のことができます(まだGNUを使用しています
grep
)。find ~/Documents -type f -exec sh -c 'for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done' Milledgeville {} +
入力を提供する前に、一連のNUL文字を改行文字に変換してください
grep
。これは、スパースファイルによって問題が発生する状況を扱います。大容量ファイルに対してのみこれを実行して最適化できます。
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 {} + \)
ファイルいいえ
grep
まれで古いバージョンのGNUを使用している場合は、2.6
このオプションを使用できます--mmap
。行はメモリにコピーされず、メモリにマップされます。つまり、システムは常にファイルページアウトを介してメモリを回復できます。このオプションはgrep
GNU 2.6から削除されました。
答え2
私は通常そうする
find ~/Documents | xargs grep -ne 'expression'
いくつかの方法を試してみたところ、この方法が最速であることがわかりました。名前にスペースが含まれるファイルはうまく処理されません。この状況を知っていて、grepのGNUバージョンがある場合は、次のものを使用できます。
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
それ以外の場合は、次のものを使用できます。
find ~/Documents -exec grep -ne 'expression' "{}" \;
これにより、exec
各ファイルに対してgrep操作が実行されます。
答え3
この問題を解決するいくつかの方法を考えることができます。
すべてのファイルを一度にインポートするのではなく、一度に1つのファイルだけを操作してください。例:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
どのファイルにこれらの単語が含まれているかを知りたい場合は、代わりにこれを行い
grep -l
ます。 grepは最初のヒット後に検索を停止するので、大容量ファイルを読み続ける必要はありません。実際のテキストも必要な場合は、2つの別々のgrepを一緒にまとめることができます。
for file in $( grep -Rl Milledgeville /Documents ); do \ grep -H Milledgeville "$file"; done
答え4
失われたデータを取得し、メモリ不足エラーが発生するように6TBディスクを準備しています。これは他のファイルにも当てはまります。
私たちが考えた解決策は、ddとgrepを使ってディスクブロックを読み取ることでした。コードは次のとおりです(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