extraia de linha em linha e salve em um arquivo separado

extraia de linha em linha e salve em um arquivo separado

Tentei a sorte grepe sedmas de alguma forma não consigo acertar.

Eu tenho um arquivo de log com cerca de 8 GB de tamanho. Preciso analisar um período de 15 minutos de atividade suspeita. Localizei a parte do arquivo de log que preciso examinar e estou tentando extrair essas linhas e salvá-las em um arquivo separado. Como eu faria isso em uma máquina CentOS normal?

Minha última tentativa foi essa, mas não funcionou. Estou perdido quando se trata seddesse tipo de comando.

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

Responder1

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

pé para impressão

Responder2

Provavelmente a melhor maneira de fazer isso é redirecionando o shell, como outros mencionaram. sedembora, embora seja um favorito pessoal, provavelmente não fará isso com mais eficiência do que o fará head- que foi projetado para capturar apenas algumas linhas de um arquivo.

Existem outras respostas neste site que mostram comprovadamente que, para arquivos grandes, head -n[num] | tail -n[num]o desempenho será sedsempre superior, mas provavelmente ainda mais rápido do que evitar completamente o canal.

Criei um arquivo como:

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

E eu analisei:

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

Eu só usei sedlá para pegar apenas a primeira e a última linha para mostrar a vocês ...

2762818
2853648

Isso funciona porque quando você agrupa comandos { ... ; }e redireciona a entrada para o grupo, ... ; } <inputtodos eles compartilharão a mesma entrada. A maioria dos comandos esgotará todo o infile durante a leitura, portanto, em um { cmd1 ; cmd2; } <infilecaso, geralmente cmd1lê do início ao final do infile e cmd2não fica sem nenhum.

head, no entanto, sempre buscará apenas até onde for instruído a fazer, e assim em um...

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

...caso o primeiro procure [num]e despeje sua saída /dev/nulle o segundo seja deixado para iniciar sua leitura onde o primeiro o deixou.

Você pode fazer...

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

Essa construção também funciona com outros tipos de comandos compostos. Por exemplo:

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

...que imprime...

2762818
2853648

Mas também pode funcionar como:

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

Acima do shell inicialmente define as variáveis $n​​​​e $dcomo ...

  • $n
    • A contagem de linhas conforme relatada por wcpara meu arquivo de teste/tmp/5mil_lines
  • $d
    • O quociente de $n/43onde 43 é apenas um divisor selecionado arbitrariamente.

Em seguida, ele faz um loop untilque diminuiu $npara $dum valor less $d. Ao fazer isso, ele salva sua contagem dividida $se usa esse valor no loop para incrementar o >arquivo de saída nomeado chamado /tmp/[num].split. O resultado é que ele lê um número igual de \ncampos delimitados por ewline em seu arquivo de entrada para um novo arquivo de saída para cada iteração - dividindo-o igualmente 43 vezes ao longo do loop. Ele gerencia isso sem ter que ler seu arquivo de entrada mais de 2 vezes - a primeira vez é quando wcele conta suas linhas e, no resto da operação, ele lê apenas quantas linhas escreve no arquivo de saída a cada vez.

Depois de executá-lo, verifiquei meus resultados como ...

tail -n1 /tmp/*split | grep .

SAÍDA:

==> /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 

Responder3

Você provavelmente poderia conseguir isso com a ajuda de combinações de headcomandos tailcomo abaixo.

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

Substitua from_line_numbere to_line_numberpelos números de linha desejados.

Teste

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

informação relacionada