Две потенциальных проблемы:
grep -R
(за исключением измененного GNU grep
найденный на OS/X 10.8 и выше), следует за символьными ссылками, поэтому даже если существует только 100 ГБ файлов в ~/Documents
, могла бы все еще быть символьная ссылка на /
например, и Вы закончите тем, что сканировали целую файловую систему включая файлы как /dev/zero
. Использовать grep -r
с более новым GNU grep
, или используйте стандартный синтаксис:
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(однако обратите внимание, что статус выхода не отразит то, что шаблон подобран или не).
grep
находит строки, которые соответствуют шаблону. Для этого это должно загрузить одну строку за один раз в памяти. GNU grep
в противоположность многим другой grep
реализации не имеют предела на размер строк, он читает и поддерживает поиск в двоичных файлах. Так, если у Вас будет файл с очень большой строкой (то есть, с двумя символами новой строки очень далеко независимо), больше, чем доступная память, то это перестанет работать.
Это обычно происходило бы с редким файлом. Можно воспроизвести его с:
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 {} + \)
Если файлы не редки, и у Вас есть версия GNU grep
до 2.6
, можно использовать --mmap
опция. Строки будут отображены в памяти в противоположность скопированному там, что означает, что система может всегда исправлять память подкачкой страниц страницы в файл. Та опция была удалена в GNU grep
2.6
Я обычно делаю
find ~/Documents | xargs grep -ne 'expression'
Я попробовал набор методов и нашел, что это было самым быстрым. Обратите внимание, что это не обрабатывает файлы с пробелами имя файла очень хорошо. Если Вы знаете дело обстоит так и имеете версию GNU grep, можно использовать:
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
Если не можно использовать:
find ~/Documents -exec grep -ne 'expression' "{}" \;
Который будет exec
grep для каждого файла.
find -print0
и xargs -0
к настоящему времени: все три BSD, MINIX 3, Солярис 11, …
– Gilles 'SO- stop being evil'
11.09.2013, 00:21
Я могу думать о нескольких способах обойти это:
Вместо того, чтобы захватить все файлы сразу, сделайте один файл за один раз. Пример:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
Если только необходимо знать, какие файлы содержат слова, сделать grep -l
вместо этого. Так как grep там прекратит искать после первого хита это не должно будет продолжать читать любые огромные файлы
Если Вы действительно хотите фактический текст также, Вы могли бы обмануть двум отдельным властям:
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
grep
выводы с помощью разделителя, который законен в именах файлов). Также необходимо заключить в кавычки $file
.
– Chris Down
10.09.2013, 14:05
for
обработать файл как два аргумента)
– Drav Sloan
10.09.2013, 14:12
Я просматриваю диск объемом 6 ТБ для поиска потерянных данных и получаю ошибку «Память исчерпана» -. Это должно работать и для других файлов.
Решение, которое мы придумали, состояло в том, чтобы читать диск порциями с помощью dd и выполнять поиск по частям. Это код (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
grep
может отбросить буферы, которые это обработало до сих пор. Вы можетеgrep
выводyes
неограниченно долго не используя больше, чем несколько килобайтов памяти. Проблемой является размер строк. – Stéphane Chazelas 10.09.2013, 15:51--null-data
опция может также быть полезной здесь. Это вызывает использование NUL вместо новой строки как входной разделитель строки. – iruvar 16.09.2013, 18:27