Что является хорошим способом извлечь, скажем, строки 20 -45 из огромного текстового файла. Не в интерактивном режиме, конечно!
Что является хорошим способом извлечь, скажем, строки 20 -45 из огромного текстового файла. Не в интерактивном режиме, конечно!
Ответы:
Вы можете попробовать:
cat textfile | head -n 45 | tail -n 26
или же
cat textfile | awk "20 <= NR && NR <= 45"
Обновить:
Как отметил Махомедалид, cat
это не обязательно и немного избыточно, но это делает для чистой, удобочитаемой команды.
Если cat
вас это беспокоит, лучшим решением будет:
<textfile awk "20 <= NR && NR <= 45"
,
оператор диапазона awk .
Еще проще:
sed -n '20,45p;45q' < textfile
Флаг -n отключает вывод по умолчанию. «20,45» адресует строки с 20 по 45 включительно. Команда "p" печатает текущую строку. И q выходит после печати строки.
q
команды (все, начиная с ;
) улучшило производительность при извлечении одной строки 26995107 из файла 27169334 строки.
Это не ответ, но я не могу опубликовать его как комментарий.
Другой (очень быстрый) способ сделать это предложил mikeserv здесь :
{ head -n 19 >/dev/null; head -n 26; } <infile
Используя тот же тестовый файл, что и здесь, и ту же процедуру, вот несколько тестов (извлечение строк 1000020-1000045):
mikeserv :
{ head -n 1000019 >/dev/null; head -n 26; } <iplist
real 0m0.059s
Стефан :
head iplist -n 1000045 | tail -n 26
real 0m0.054s
Это, безусловно, самые быстрые решения, и различия незначительны (для одного прохода) (я пробовал с разными диапазонами: пара строк, миллионы строк и т. Д.).
Однако выполнение этого без конвейера может принести существенное преимущество приложению, которому необходимо выполнить поиск по нескольким диапазонам линий аналогичным образом, например:
for pass in 0 1 2 3 4 5 6 7 8 9
do printf "pass#$pass:\t"
head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES
... который печатает ...
pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000
... и читает файл только один раз.
Другие sed
/ awk
/ perl
решения читают весь файл, и поскольку речь идет об огромных файлах, они не очень эффективны. Я добавил несколько вариантов, которые exit
или q
uit после последней строки в указанном диапазоне:
Стефан :
awk "1000020 <= NR && NR <= 1000045" iplist
real 0m2.448s
против
awk "NR >= 1000020;NR==1000045{exit}" iplist
real 0m0.243s
dkagedal ( sed
):
sed -n 1000020,1000045p iplist
real 0m0.947s
против
sed '1,1000019d;1000045q' iplist
real 0m0.143s
Стивен Д :
perl -ne 'print if 1000020..1000045' iplist
real 0m2.041s
против
perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist
real 0m0.369s
awk NR==1000020,NR==1000045 textfile
в вашей системе.
ruby -ne 'print if 20 .. 45' file
python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'
? :-P Это то, что Ruby, созданный по образцу Perl, вдохновленный awk / sed, может сделать легко.
Поскольку sed и awk уже были заняты, вот решение perl:
perl -nle "print if ($. > 19 && $. < 46)" < textfile
Или, как указано в комментариях:
perl -ne 'print if 20..45' textfile
perl -ne'print if 20..45' textfile
awk NR==20,NR==45 textfile
тоже работает и легко читается.