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

141

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

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

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

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

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

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

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

15 ответов

57
Лучший ответ

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

grep --context=10 ...
  • 7
    Точнее 10 строк до: grep -B 10 ... Или 10 строк после: grep -A 10 ...
  • 11
    Эта команда не работает, ниже sed -n '<start>, <end> p' работает
Показать ещё 3 комментария
326

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

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

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

или

awk 'FNR>=20 && FNR<=40' file_name
  • 5
    +1: хотя вы можете выйти после печати. Может предложить некоторые преимущества в производительности, если файл действительно огромен.
  • 0
    awk 'NR> = 20 && NR <= 40' имя_файла
Показать ещё 3 комментария
77
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

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

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

  • 0
    Я пытаюсь понять, как адаптировать метод 3 для использования диапазона вместо одной строки, но я боюсь, что мой сед-фу не справится с этой задачей.
  • 7
    @XiongChiamiov Как насчет sed -n '1500p; 501q' для печати 1-500?
20

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

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

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

  • 6
    Ты прав; нет короткого пути.
  • 2
    Если строки не имеют фиксированной ширины в байтах, вы не знаете, куда перемещать указатель файла, не считая символов новой строки в начале файла.
Показать ещё 2 комментария
18

Как насчет:

tail -n +347340107 filename | head -n 100

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

  • 0
    Нет, обычно хвост имеет ограничение в 256 последних килобайт или подобное, в зависимости от версии и ОС.
12

Сначала я разделил файл на несколько меньших, например,

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

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

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

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

  • введите 5 0 %, чтобы перейти на полпути файла,
  • 43210 G, чтобы перейти к строке 43210
  • :43210 сделать то же самое

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

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

6

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

  • отображает одну строку (например, вторую):

    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!).
4

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

2

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

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

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

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

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

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

sed -n "${x},${x+100}p" <file>
  • 0
    Если у вас более одного совпадения, используйте: «awk 'NR == 1 {print $ 1}» для первого совпадения и т. Д.
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
}
2

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

0

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

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd
  • 1
    Вы говорите, что это легко с awk, но вместо этого вы сделали это в perl?
0

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

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

Чтобы отобразить строку из <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, поскольку это зрелый язык, имеет много скрытых улучшений, способствующих быстроте и производительности. Имея это в виду, это делает его очевидным выбором для такой операции, поскольку он был первоначально разработан для обработки больших файлов журнала, текста, баз данных и т.д.

  • 0
    Я думаю, что это более сложный ответ ...
  • 0
    на самом деле, мне так не кажется, так как, когда одна команда perl выполняется сложнее, чем, скажем, запуск более 2 программ по конвейеру (далее по странице), и, я думаю, вы на самом деле говорите, потому что я набрал больше объяснение, которое требовало от вас ПРОЧИТАТЬ, так как есть одинаково сложные (или более) страницы, которые не вылетели из воды ... sheesh
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню