Быстрая команда Unix для отображения определенных строк в середине файла?


207

Попытка отладить проблему с сервером, и мой единственный файл журнала - это файл журнала 20 ГБ (даже без отметок времени! Почему люди используют System.out.println()для ведения журнала? В производстве ?!)

Используя grep, я нашел область файла, на которую я хотел бы взглянуть, строка 347340107.

Кроме того, чтобы делать что-то вроде

head -<$LINENUM + 10> filename | tail -20 

... что потребует headпрочтения первых 347 миллионов строк файла журнала, есть ли быстрая и простая команда, которая выводит строки 347340100 - 347340200 (например) на консоль?

обновление Я полностью забыл, что grep может печатать контекст вокруг совпадения ... это хорошо работает. Спасибо!


Я полагаю, что grep должен искать по всему файлу, должен быть процессор, менее интенсивный способ сделать это.
ojblass

Ответы:


70

с GNU-grep вы можете просто сказать

grep --context = 10 ...

7
А точнее 10 строк до: grep -B 10 ... Или 10 строк после: grep -A 10 ...
Boy Baukema

17
Эта команда не работает, ниже sed -n '<start>, <end> p' работает
Basav

5
Это на самом деле не то, что вы хотите, потому что он будет обрабатывать весь файл, даже если совпадение находится в верхнем бите. На этом этапе комбо голова / хвост или хвост / голова намного эффективнее.
Скливвз

3
Это не удовлетворяет заданному вопросу вообще, поскольку это не предлагает способ вывести определенную строку , как было задано.
Крис Расис

1
Это на самом деле не то, что спросили. @ Матт б, почему бы тебе не принять этот ответ?
user1271772

391

Я нашел два других решения, если вы знаете номер строки, но больше ничего (нет возможности grep):

Предполагая, что вам нужны строки от 20 до 40,

sed -n '20,40p;41q' file_name

или

awk 'FNR>=20 && FNR<=40' file_name

6
+1: хотя вы можете выйти после печати. Может предложить некоторые преимущества в производительности, если файл действительно большой.
Джайпал Сингх

awk 'NR> = 20 && NR <= 40' имя_файла
Судипта Басак

2
sed -n '20, 40p; 41q 'имя_файла для выхода тогда.
Снигдха Батра

1
в частности, это номера начала и конца строки. Если вы находитесь в файле большего размера, это будет «12345678,12345699p»
Code Abominator

1
В дополнение к комментарию @ CodeAbominator 41qпроинструктируйте sed выйти из очереди 41.
Брайс

116
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

Метод 3 эффективен для больших файлов

самый быстрый способ отображения определенных строк


Я пытаюсь понять, как адаптировать метод 3 для использования диапазона вместо одной строки, но я боюсь, что мой сед-фу не справится с этой задачей.
Сюн Чиамов

9
@XiongChiamiov Как насчет sed -n '1500p; 501q' для печати 1-500?
Сэм

3
Причина, по которой первые две строки / методы менее эффективны, заключается в том, что они продолжают обрабатывать все строки после строки 52 до конца, тогда как # 3 останавливается после печати строки 52.
flow2k

1
Этот ответ выиграл бы от объяснения того, что делают все аргументы.
Брэм Ванрой

25

Нет, файлы не являются адресно-строковыми.

Нет постоянного способа найти начало строки n в текстовом файле. Вы должны пройти через файл и считать новые строки.

Используйте самый простой / быстрый инструмент, который вам нужен для работы. Для меня использование headимеет гораздо больше смысла, чем grep, так как последнее намного сложнее. Я не говорю « grepмедленно», это действительно не так, но я был бы удивлен, если бы это было быстрее, чем headв этом случае. Это было бы ошибкой, в headосновном.


2
Если строки не имеют фиксированной ширины в байтах, вы не знаете, куда перемещать указатель файла, не считая символы новой строки в начале файла.
Джозеф Ласт

Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под своим постом.
exhuma

@ exhuma Ты прав. Я переписал. Семь лет назад меня разозлили. :)
расслабиться

20

Что о:

tail -n +347340107 filename | head -n 100

Я не проверял это, но думаю, что это сработает.


Нет, обычно хвост имеет ограничение в 256 последних килобайт или подобное, в зависимости от версии и ОС.
Антти Рыцёля

💪 yessire мельник
dctremblay

13

Я предпочитаю просто войти lessи

  • набрав 50%половину файла,
  • 43210G перейти на линию 43210
  • :43210 сделать то же самое

и тому подобное.

Еще лучше: нажмите, vчтобы начать редактирование (в vim, конечно!), В этом месте. Теперь обратите внимание, что vimимеет такие же привязки клавиш!


12

Сначала я бы разделил файл на несколько таких маленьких

$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix

а затем grep на полученные файлы.


согласитесь, прервите эту регистрацию и создайте работу cron, чтобы сделать это правильно. используйте logrotate или что-то подобное, чтобы они не становились такими огромными.
Tanj

9

Вы можете использовать exкоманду, стандартный редактор Unix (теперь это часть Vim), например

  • отобразить одну строку (например, 2-ую):

    ex +2p -scq file.txt

    соответствующий синтаксис sed: sed -n '2p' file.txt

  • диапазон строк (например, 2-5 строк):

    ex +2,5p -scq file.txt

    Синтаксис sed: sed -n '2,5p' file.txt

  • от заданной строки до конца (например, с 5-го по конец файла):

    ex +5,p -scq file.txt

    Синтаксис sed: sed -n '2,$p' file.txt

  • несколько строк (например, 2-4 и 6-8 строк):

    ex +2,4p +6,8p -scq file.txt

    Синтаксис sed: sed -n '2,4p;6,8p' file.txt

Указанные выше команды могут быть протестированы с помощью следующего тестового файла:

seq 1 20 > file.txt

Объяснение:

  • +или -cпосле команды - выполнить команду (vi / vim) после прочтения файла,
  • -s - тихий режим, также использует текущий терминал в качестве выхода по умолчанию,
  • qзатем следует -cкоманда для выхода из редактора (например, добавьте !для принудительного выхода -scq!).

7

Если ваш номер строки 100 читать

head -100 filename | tail -1

6

Получить ack

Установка Ubuntu / Debian:

$ sudo apt-get install ack-grep

Затем запустите:

$ ack --lines=$START-$END filename

Пример:

$ ack --lines=10-20 filename

От $ man ack:

--lines=NUM
    Only print line NUM of each file. Multiple lines can be given with multiple --lines options or as a comma separated list (--lines=3,5,7). --lines=4-7 also works. 
    The lines are always output in ascending order, no matter the order given on the command line.

1
Мне кажется, что это команда с наиболее понятным синтаксисом из всех ответов здесь.
NZN

С версии 2.999_06 10 января 2019 года --linesпараметр был удален.
бурный

4

Sed должен будет прочитать данные, чтобы посчитать строки. Единственный способ, которым ярлык был бы возможен, был бы контекст / порядок в файле, чтобы работать с ним. Например, если были строки журнала с предустановленной датой / временем ширины и т. Д., Вы можете использовать утилиту look unix для двоичного поиска в файлах по определенным датам / временам.


4

использование

x=`cat -n <file> | grep <match> | awk '{print $1}'`

Здесь вы получите номер строки, где произошло совпадение.

Теперь вы можете использовать следующую команду для печати 100 строк

awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>

или вы можете использовать «седь»

sed -n "${x},${x+100}p" <file>

Если у вас есть более одного совпадения, используйте: «awk 'NR == 1 {print $ 1}» для первого матча и так далее
Рамана Редди

2

При этом sed -e '1,N d; M q'вы будете печатать строки от N + 1 до M. Это, вероятно, немного лучше, так grep -Cкак он не пытается сопоставить линии с шаблоном.


-eздесь необязательно.
flow2k

2

Основываясь на ответе Sklivvz, вот хорошая функция, которую можно поместить в .bash_aliasesфайл. Он эффективен при работе с большими файлами при печати содержимого с начала файла.

function middle()
{
    startidx=$1
    len=$2
    endidx=$(($startidx+$len))
    filename=$3

    awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}

1

Чтобы отобразить строку из <textfile>ее <line#>, просто сделайте это:

perl -wne 'print if $. == <line#>' <textfile>

Если вы хотите более эффективный способ показать диапазон строк с регулярными выражениями - я не буду говорить, почему grep - плохая идея для этого, это должно быть довольно очевидно - это простое выражение покажет вам ваш диапазон в один проход, который вам нужен при работе с ~ 20 ГБ текстовыми файлами:

perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>

(Совет: если ваше регулярное выражение имеет /в нем, используйте что-то вродеm!<regex>! этого)

Это напечатало бы, <filename>начиная со строки, которая соответствует <regex1>вплоть до (и включая) строку, которая соответствует<regex2> .

Не нужно волшебника, чтобы увидеть, как несколько настроек могут сделать его еще более мощным.

И последнее: Perl, поскольку он является зрелым языком, имеет множество скрытых улучшений, способствующих скорости и производительности. Имея это в виду, это делает очевидным выбор для такой операции, поскольку она изначально была разработана для обработки больших файлов журналов, текста, баз данных и т. Д.


на самом деле, мне так не кажется, потому что когда одна команда Perl выполняется сложнее, чем, скажем, запуск более 2 программ по конвейеру (далее по странице), и, я думаю, вы на самом деле говорите, потому что я набрал больше объяснение, которое требовало от вас ПРОЧИТАТЬ, так как есть не менее сложные (или более) страницы, которые не
вылетели

Обратите внимание, что пользователь запросил диапазон строк - ваш пример может быть тривиально адаптирован.
Скливвз


0

Легко с Perl! Если вы хотите получить строки 1, 3 и 5 из файла, скажите / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

1
Вы говорите, что это легко с awk, но вместо этого вы сделали это в perl?
Заключенный 13

0

Я удивлен, что только один другой ответ (Рамана Редди) предложил добавить номера строк к выводу. Следующий поиск ищет требуемый номер строки и окрашивает вывод.

file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }

Ответы с кодом, как правило, помечаются для удаления. Не могли бы вы добавить комментарий о том, как это решает проблему?
Грэм
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.