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

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

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

кроме как делать что-то вроде

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

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

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

18 ответов


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

grep --context=10 ...

Я нашел еще два решений если вы знаете номер строки, но ничего другого (без поиска):

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

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

или

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

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

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

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


нет, файлы не адресно.

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

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


о:

tail -n +347340107 filename | head -n 100

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


Я бы сначала разделил файл на несколько меньших, таких как этот

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

, а затем grep на результирующих файлах.


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

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

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

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


вы можете использовать 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 - команда выхода из редактора (add ! сделать force quit, например -scq!).

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


использовать

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

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

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

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

или вы можете использовать "sed", а также

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

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


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

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

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

получить ack

ack --lines=начальное имя файла


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

head -100 filename | tail -1

для отображения строки из <textfile> его <line#> - просто делай это:

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

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

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

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

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

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

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


вы можете попробовать эту команду:

egrep -n "*" <filename> | egrep "<line number>"

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

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

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

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:]]"; }