извлечь построчно и сохранить в отдельный файл

извлечь построчно и сохранить в отдельный файл

Я попытал счастья с grepи , sedно почему-то у меня не получилось сделать это правильно.

У меня есть файл журнала размером около 8 ГБ. Мне нужно проанализировать 15-минутный период подозрительной активности. Я нашел часть файла журнала, которую мне нужно просмотреть, и пытаюсь извлечь эти строки и сохранить их в отдельный файл. Как мне это сделать на обычной машине CentOS?

Моя последняя попытка была такой, но она не сработала. Я в растерянности, когда дело доходит до sedкоманд такого типа.

sed -n '2762818,2853648w /var/log/output.txt' /var/log/logfile

решение1

sed -n '2762818,2853648p' /var/log/logfile > /var/log/output.txt

pдля печати

решение2

Вероятно, лучшим способом сделать это является перенаправление оболочки, как уже упоминали другие. sedХотя, хотя это и мой любимый способ, он, вероятно, не сделает это эффективнее, чем will head, который предназначен для извлечения только определенного количества строк из файла.

На этом сайте есть и другие ответы, которые наглядно показывают, что для больших файлов это всегда head -n[num] | tail -n[num]будет лучше sed, но, вероятно, даже быстрее будет вообще отказаться от конвейера.

Я создал такой файл:

echo | dd cbs=5000000 conv=block | tr \  \\n >/tmp/5mil_lines

И я прогнал это:

{ head -n "$((ignore=2762817))" >&2
  head -n "$((2853648-ignore))" 
} </tmp/5mil_lines 2>/dev/null  |
sed -n '1p;$p'                

Я использовал sedего только для того, чтобы захватить только первую и последнюю строчку, чтобы показать вам...

2762818
2853648

Это работает, потому что когда вы группируете команды { ... ; }и перенаправляете ввод для группы, как будто ... ; } <inputвсе они будут использовать один и тот же ввод. Большинство команд исчерпывают весь infile при его чтении, поэтому в { cmd1 ; cmd2; } <infileслучае обычно cmd1считывает от начала infile к его концу и cmd2не остается ничего.

head, однако, всегда будет искать только в той части своего входного файла, которая ему указана, и поэтому в...

{ head -n [num] >/dev/null
  head -n [num]
} <infile 

...если первый ищет [num]и выгружает свой вывод, /dev/nullа второй остается, чтобы начать чтение с того места, где его остановил первый.

Ты можешь сделать...

{ head -n "$((ignore=2762817))" >/dev/null
  head -n "$((2853648-ignore))" >/path/to/outfile
} <infile

Эта конструкция также работает с другими видами составных команд. Например:

set "$((n=2762817))" "$((2853648-n))"
for n do head "-n$n" >&"$#"; shift
done <5mil_lines 2>/dev/null | 
sed -n '1p;$p'

...который печатает...

2762818
2853648

Но это также может работать так:

d=$(((  n=$(wc -l </tmp/5mil_lines))/43 ))      &&
until   [ "$(((n-=d)>=(!(s=143-n/d))))" -eq 0 ] &&
        head "-n$d" >>"/tmp/${s#1}.split"
do      head "-n$d" > "/tmp/${s#1}.split"       || ! break
done    </tmp/5mil_lines

Вышеуказанная оболочка изначально устанавливает переменные $nи $dв ...

  • $n
    • Количество строк, указанное wcдля моего тестового файла/tmp/5mil_lines
  • $d
    • Частное, $n/43где 43 — это просто некоторый произвольно выбранный делитель.

Затем он выполняет цикл, на untilкоторый он уменьшился на значение меньше . При этом он сохраняет свой счетчик разделений в и использует это значение в цикле для увеличения именованного выходного файла с именем . Результатом является то, что он считывает равное количество полей с разделителями ewline в своем входном файле в новый выходной файл для каждой итерации — разделяя его поровну 43 раза в течение цикла. Он справляется с этим, не считывая свой входной файл более 2 раз — первый раз, когда он делает это, чтобы подсчитать свои строки, а для остальной части операции он считывает только столько строк, сколько записывает в выходной файл каждый раз.$n$d$d$s>/tmp/[num].split\nwc

После запуска я проверил результаты, как...

tail -n1 /tmp/*split | grep .

ВЫХОД:

==> /tmp/01.split <==
116279  
==> /tmp/02.split <==
232558  
==> /tmp/03.split <==
348837  
==> /tmp/04.split <==
465116  
==> /tmp/05.split <==
581395  
==> /tmp/06.split <==
697674  
==> /tmp/07.split <==
813953  
==> /tmp/08.split <==
930232  
==> /tmp/09.split <==
1046511 
==> /tmp/10.split <==
1162790 
==> /tmp/11.split <==
1279069 
==> /tmp/12.split <==
1395348 
==> /tmp/13.split <==
1511627 
==> /tmp/14.split <==
1627906 
==> /tmp/15.split <==
1744185 
==> /tmp/16.split <==
1860464 
==> /tmp/17.split <==
1976743 
==> /tmp/18.split <==
2093022 
==> /tmp/19.split <==
2209301 
==> /tmp/20.split <==
2325580 
==> /tmp/21.split <==
2441859 
==> /tmp/22.split <==
2558138 
==> /tmp/23.split <==
2674417 
==> /tmp/24.split <==
2790696 
==> /tmp/25.split <==
2906975 
==> /tmp/26.split <==
3023254 
==> /tmp/27.split <==
3139533 
==> /tmp/28.split <==
3255812 
==> /tmp/29.split <==
3372091 
==> /tmp/30.split <==
3488370 
==> /tmp/31.split <==
3604649 
==> /tmp/32.split <==
3720928 
==> /tmp/33.split <==
3837207 
==> /tmp/34.split <==
3953486 
==> /tmp/35.split <==
4069765 
==> /tmp/36.split <==
4186044 
==> /tmp/37.split <==
4302323 
==> /tmp/38.split <==
4418602 
==> /tmp/39.split <==
4534881 
==> /tmp/40.split <==
4651160 
==> /tmp/41.split <==
4767439 
==> /tmp/42.split <==
4883718 
==> /tmp/43.split <==
5000000 

решение3

Вероятно, вы могли бы добиться этого с помощью комбинаций headкоманд tail, как показано ниже.

head -n{to_line_number} logfile | tail -n+{from_line_number} > newfile

Замените from_line_numberи to_line_numberнужными вам номерами строк.

Тестирование

cat logfile
This is first line.
second
Third
fourth
fifth
sixth
seventh
eighth
ninth
tenth

##I use the command as below. I extract from 4th line to 10th line. 

head -n10 logfile | tail -n+4 > newfile
fourth
fifth
sixth
seventh
eighth
ninth
tenth

Связанный контент