非常に単純な検索を行っていました:
grep -R Milledgeville ~/Documents
そしてしばらくすると、このエラーが表示されました:
grep: memory exhausted
これを回避するにはどうすればよいですか?
システムに10GBのRAMがあり、アプリケーションがほとんどありません実行中なので、単純なgrepのメモリが不足していることに本当に驚いています。 ~/Documents
は約100GBで、あらゆる種類のファイルが含まれています。
grep -RI
にはこの問題はないかもしれませんが、必要です。バイナリファイルも検索します。
回答
2つの潜在的な問題:
-
grep -R
(OS / X10.8以降で見つかった変更されたGNUgrep
を除く)はシンボリックリンクをたどるので、~/Documents
に100GBのファイルがある場合、たとえば/
へのシンボリックリンクが残っている可能性があり、ファイルシステム全体をスキャンすることになります。/dev/zero
のようなファイル。grep -r
を新しいGNUgrep
で使用するか、標準の構文を使用します:find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(ただし、終了ステータスはパターンが一致するかどうかを反映しないことに注意してください)。
-
grep
は、パターンに一致する行を検索します。そのためには、メモリに一度に1行ずつロードする必要があります。他の多くのiv id = “cc67858b36″とは対照的に、GNUgrep
>
の実装では、読み取る行のサイズに制限はなく、バイナリファイルでの検索をサポートします。したがって、使用可能なメモリよりも大きい非常に大きな行(つまり、2つの改行文字が非常に遠い)のファイルがある場合、失敗します。
これは通常、スパースファイル。次のコマンドで再現できます:
truncate -s200G some-file grep foo some-file
これは回避が困難です。(GNU ):
find ~/Documents -type f -exec sh -c "for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done" Milledgeville {} +
入力を。これは、問題がスパースファイルに起因する場合をカバーします。
大きなファイルに対してのみ実行することで最適化できます:
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 {} + \)
ファイルがスパースではなく 、iv id =” 14dfe9e720 “より前のバージョンのGNU grep
がある場合>
、--mmap
オプションを使用できます。行はメモリにコピーされるのではなく、メモリにマッピングされます。つまり、システムはいつでもメモリを再利用できます。 yページをファイルにページアウトします。このオプションはGNU grep
2.6
コメント
回答
私は通常そうします
find ~/Documents | xargs grep -ne "expression"
たくさんの方法を試しましたが、これが最速であることがわかりました。これは、ファイル名にスペースが含まれるファイルを適切に処理しないことに注意してください。これが当てはまり、grepのGNUバージョンがある場合は、次を使用できます。
find ~/Documents -print0 | xargs -0 grep -ne "expression"
使用できない場合:
find ~/Documents -exec grep -ne "expression" "{}" \;
すべてのファイルのgrepをexec
します。
コメント
- スペースのあるファイルでは壊れます。
- うーん、そうです。
- これは、
find -print0 | xargs -0 grep -ne 'expression'
- @ChrisDownを使用すると、壊れたポータブルソリューションではなく、収益性の低いソリューションで回避できます。
- @ChrisDown Most主要なユニスは、現在
find -print0
とxargs -0
を採用しています。3つすべてのBSD、MINIX 3、Solaris 11、…
回答
これを回避する方法はいくつか考えられます:
-
代わりにすべてのファイルを一度にgrepする場合は、一度に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
コメント
- 最後の例は有効な構文ではありません-'コマンド置換を実行する必要があります('は、'を実行しないでください。 = “cc67858b36″>
は、ファイル名で有効な区切り文字を使用して出力します。また、$file
を引用する必要があります。
for
がファイルを2つの引数として処理します)回答
6TBのディスクをgrepして失われたデータを検索し、メモリが使い果たされました-エラー。これは他のファイルでも機能するはずです。
私たちが思いついた解決策は、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
コメント
- 読んでいない限りオーバーラップチャンクの場合、チャンク境界での一致を見逃す可能性があります。オーバーラップは、少なくとも一致する予定の文字列と同じ大きさである必要があります。
- 100MBのチャンクごとに1MB余分に検索するように更新されました…安価なハック
grep
はこれまでに処理したバッファを破棄できます。grep
yes
の出力は、数キロバイトを超えるメモリを使用せずに無期限に実行できます。問題は行のサイズです。--null-data
オプションもここで役立つ場合があります。入力行ターミネーターとして改行の代わりにNULを強制的に使用します。dd if=/dev/sda | fold -b $((4096*1024*1024)) | grep -a "some string"
を考えて必要なメモリ量を4GBに制限します