回答:
2つの潜在的な問題:
grep -R
(grep
OS / X 10.8以降で見つかった変更されたGNUを除く)はシンボリックリンクに従うため、に100GBのファイルしかない場合~/Documents
でも/
、たとえばへのシンボリックリンクが残っている可能性があり、ファイルを含むファイルシステム全体をスキャンすることになりますのような/dev/zero
。使用するgrep -r
新しいGNUでgrep
、または標準の構文を使用します。
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(ただし、終了ステータスはパターンが一致するかどうかを反映しないことに注意してください)。
grep
パターンに一致する行を見つけます。そのためには、メモリに一度に1行をロードする必要があります。grep
他の多くのgrep
実装とは対照的に、GNU は読み込む行のサイズに制限がなく、バイナリファイルでの検索をサポートしています。そのため、非常に大きな行(つまり、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文字のシーケンスを1つの改行文字に変換し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
場合、このオプションを使用できます。行はメモリにコピーされるのではなく、メモリにマップされます。つまり、システムは、ページをファイルにページアウトすることにより、常にメモリを再利用できます。そのオプションはGNU grep
2.6で削除されました
grep
それまでに処理したバッファを破棄できます。数キロバイト以上のメモリを使用せずgrep
にyes
無期限に出力できます。問題は、行のサイズです。
--null-data
オプションも役立ちます。入力行ターミネータとして改行の代わりにNULの使用を強制します。
私は通常やる
find ~/Documents | xargs grep -ne 'expression'
たくさんの方法を試しましたが、これが最速であることがわかりました。これは、ファイル名にスペースを含むファイルをうまく処理しないことに注意してください。これが事実であり、grepのGNUバージョンを持っていることがわかっている場合は、次を使用できます。
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
使用できない場合:
find ~/Documents -exec grep -ne 'expression' "{}" \;
これはexec
、すべてのファイルのgrepになります。
find -print0 | xargs -0 grep -ne 'expression'
find -print0
おりxargs -0
、現在では、3つのBSD、MINIX 3、Solaris 11、…
これを回避するいくつかの方法を考えることができます。
すべてのファイルを一度にgrepする代わりに、一度に1つのファイルを実行します。例:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
どのファイルに単語が含まれているかだけを知る必要がある場合は、grep -l
代わりに行います。grepは最初のヒット後に検索を停止するため、巨大なファイルを読み続ける必要はありません。
実際のテキストも必要な場合は、2つの別々のgrepsを次のように並べることができます。
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
grep
出力はファイル名で有効な区切り文字を使用しているため、実行しないでください)。引用する必要もあります$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