Вопрос: Как отобразить определенные строки из текстового файла в Linux?


Я думаю, все знают полезные утилиты Linux cmd head а также tail, head позволяет печатать первые X строк файла, tail делает то же самое, но печатает конец файла. Что такое хорошая команда для печати середины файла? что-то вроде middle --start 10000000 --count 20 (напечатайте 10'000'000-ый до 10'000'010-й строки).

Я ищу что-то, что будет эффективно обрабатывать большие файлы. Я пытался tail -n 10000000 | head 10 и это ужасно медленно.


69
2018-04-19 08:53


Источник


возможный дубликат serverfault.com/questions/101900/... - Kyle Brandt♦


Ответы:


sed -n '10000000,10000020p' filename

Возможно, вы сможете немного ускорить это:

sed -n '10000000,10000020p; 10000021q' filename

В этих командах параметр -n причины sed «подавить автоматическую печать пространства образца». p команда "напечатать [s] текущее пространство образца" и q команда «Немедленно покинуть [s] сценарий sed без обработки каких-либо дополнительных данных ...» Кавычки из sed  man страница,

Кстати, ваша команда

tail -n 10000000 filename | head 10

начинается с десятимиллионной линии от конец файла, в то время как ваша «средняя» команда, похоже, начнется с десятимиллионной начало что эквивалентно:

head -n 10000010 filename | tail 10

Проблема в том, что для несортированных файлов с переменными длинными строками любой процесс должен пройти через файл, пересчитывающий новые строки. Невозможно сократить это.

Если, однако, файл сортируется (например, файл журнала с отметками времени) или имеет фиксированные длины, то вы можете искать файл в зависимости от позиции байта. В примере файла журнала вы можете выполнить двоичный поиск в течение нескольких раз, как мой сценарий Python Вот*. В случае файла фиксированной длины записи это очень просто. Вы просто ищете linelength * linecount символов в файл.

* У меня есть смысл опубликовать еще одно обновление этого сценария. Может быть, я займусь этим на днях.


87
2018-04-19 09:11



Вот sed версия Чарльза ' middle функция: middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }, Он будет обрабатывать несколько аргументов файла, имена файлов с пробелами и т. Д. Несколько файлов обрабатываются вместе, как если бы они были помечены так же, как sed обычно (так что средний 1000 100 file1 file2 будет охватывать конец первого файла до начала второго, если первый имеет менее 1100 строк). - Dennis Williamson
Функция в моем предыдущем комментарии может быть вызвана с параметром имени файла: middle startline count filename или несколько имен файлов: middle startline count file1 file2 file3 или с перенаправлением: middle startline count < filename или в трубе: some_command | средний стартовый номер или cat file* | middle startline count - Dennis Williamson
Разве `` в вашей команде sed быть '? Я не могу заставить его работать с backtick, но он отлично работает с одной цитатой. - Ian Hunter
@beanland: Да, это опечатка. Я исправил это. Благодарю. - Dennis Williamson
@kev: Я добавил несколько объяснений в свой ответ. - Dennis Williamson


Я узнал следующее использование sed

sed -n '10000000,+20p'  filename

Надеюсь, это полезно кому-то!


24
2018-06-17 18:22



Хорошо знать, что есть альтернатива аргументу последней строки, предложенному Деннисом: количество строк как второе sed -n аргумент, который делает его вполне читаемым. - user3123159
Пример использования: extract_lines(){sed -n "$1,+$2p" <file>} который пишет в stdout. - user3123159


Это мой первый пост! Во всяком случае, это легко. Предположим, вы хотите вывести строку 8872 из файла file.txt. Вот как вы это делаете:

cat -n file.txt | grep '^ * 8872'

Теперь вопрос состоит в том, чтобы найти 20 строк после этого. Для этого вы

cat -n file.txt | grep -A 20 '^ * 8872'

Для строк вокруг или перед просмотром флагов -B и -C в руководстве grep.


4
2018-05-23 12:11



Хотя это технически корректно и интересный способ сделать это в файле с разумным размером, мне любопытно его эффективность при работе с файлами размером, о котором спрашивает плакат. - Jenny D
Несколько строк: cat -n file.txt | grep "^ \ s \ + (10 \ | 20 \ | 30) \ s \ +" - Jeff K.
cat -n file.txt | grep '^ *1' выведите все линии, которые имеют 1 с правой стороны. Как вывести строку 1 с помощью этой техники? Я знаю, что могу возглавить -n 1 .... но как использовать grep? - Sean87


Ответ Денниса - это путь. Но, используя только head & tail, под bash:

middle () {head -n $ [$ 1 + $ 2] | tail -n $ 2; }

Это дважды проверяет первые строки $ 1 + $ 2, так что намного хуже, чем ответ Денниса. Но вам не нужно помнить все эти буквы, чтобы использовать его ...


1
2018-04-19 15:08



С помощью $[...] устарел, по крайней мере, в Баше. Кроме того, вам не хватает параметра файла. - Dennis Williamson
@Dennis: Отсутствует отсутствующий параметр: вы должны использовать это на stdin, согласно middle 10 10 < /var/log/auth.log, - Charles Stewart


Используйте следующую команду, чтобы получить конкретный диапазон строк

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

Здесь debug.log - это мой файл, который состоит из недостатков строк, и я использовал для печати строк с номера строки 1220974 до 1513793 в файл test.log. надеюсь, что это будет полезно для захвата диапазона линий.


1
2018-04-17 19:48



Тот же ответ, что и serverfault.com/a/641252/140016, Downvoted. - Deer Hunter
Это не тот ответ. Это должно быть быстрее для больших файлов, поскольку оно фактически прерывается после печати последней строки, а не продолжения сканирования через файл. - phobic


Версия рубинового oneliner.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Это может быть полезно кому-то. Решения с «sed», предоставляемые Dennis и Dox, очень приятные, даже потому, что они выглядят быстрее.


0
2018-05-23 12:58





Вы можете использовать 'nl'.

nl filename | grep <line_num>

0
2017-10-31 19:35





Например, этот awk будет печатать строки от 20 до 40

awk '{if ((NR> 20) && (NR <40)) print $ 0}' / etc / passwd


0
2017-10-31 22:02