O contexto de saída (-C) para o grep produz arquivos massivos

1

Tarefa:

Estou usando grep para pesquisar alguns arquivos de texto, canalizando os resultados de um grep (excluindo algumas linhas) para outro (correspondendo algumas linhas) + exibindo algum contexto usando o parâmetro -C , conforme mostrado abaixo:

grep -v "Chapter" *.txt | grep -nE  -C1 " leaves? " 

Problema:

Isso funciona muito bem ao imprimir os resultados, mas produz arquivos muito grandes (~ vários GB) e leva uma eternidade quando eu os escrevo assim:

grep -v "Chapter" *.txt | grep -nE  -C1 " leaves? " > out.txt

Solução de problemas:

  1. O grep retorna apenas 1345 linhas (de acordo com wc ), a impressão leva alguns segundos

  2. A saída nos arquivos de saída grandes parece legítima, também conhecida como resultados reais dos arquivos de entrada.

  3. A substituição do operador -C por -A ou -B produz bons arquivos de saída no tamanho do KB.

Perguntas:

  • Por que isso está acontecendo?
  • Existe algo sobre o -C que quebra as coisas dessa maneira?
  • Ou há um problema diferente que estou negligenciando?

Quaisquer sugestões apreciadas! Executando isso no terminal MacOS. Eu estava seguindo este homem.

    
por patrick 12.08.2018 / 00:26

1 resposta

3

Tente alterar o diretório em que você está escrevendo out.txt . Por exemplo, altere este comando para isto:

$ grep -v "Chapter" *.txt | grep -nE  -C1 " leaves? " > /tmp/out.txt

Exemplo

Aqui você pode ver o que está acontecendo quando você habilita a saída detalhada no seu shell Bash.

$ set -x
$ grep -v "Chapter" *.txt | grep -nE  -C1 " leaves? " > out.txt
+ grep --color=auto -nE -C1 ' leaves? '
+ grep --color=auto -v Chapter file01.txt file02.txt file03.txt file04.txt file05.txt file06.txt file07.txt file08.txt file09.txt file10.txt out.txt

Observe que está levando o argumento *.txt e expandindo-o, e inclui o arquivo out.txt . Então você está literalmente analisando esse arquivo enquanto escreve para ele.

Por quê?

Se você pensar sobre o que um shell faz quando a saída de um comando é canalizada para o próximo, faz sentido. O shell analisa os comandos que você acabou de fornecer, procurando por pipes ( | ). Quando ele os encontra, tem que executar os da direita para configurar o redirecionamento de STDIN / STDOUT entre os comandos que ocorrem nos canais.

Você pode usar o comando sleep para ver como o shell analisa as coisas à medida que mais tubos são adicionados:

$ sleep 0.1 | sleep 0.2 | sleep 0.3 | sleep 0.4
+ sleep 0.2
+ sleep 0.3
+ sleep 0.4
+ sleep 0.1

$ sleep 0.1 | sleep 0.2 | sleep 0.3 | sleep 0.4 | sleep 0.5
+ sleep 0.2
+ sleep 0.3
+ sleep 0.4
+ sleep 0.5
+ sleep 0.1

Fazer isso com echo + escrevendo em um arquivo também mostra a ordem através dos acessos ao arquivo & o comando stat :

$ echo "1" > file1 | echo "2" > file2 | echo "3" > file3 | echo "4" > file4
+ echo 2
+ echo 3
+ echo 4
+ echo 1

$ stat file* | grep -E "File|Access: [[:digit:]]+"
+ grep --color=auto -E 'File|Access: [[:digit:]]+'
+ stat file1 file2 file3 file4
  File: ‘file1’
Access: 2018-08-11 23:55:20.868220474 -0400
  File: ‘file2’
Access: 2018-08-11 23:55:20.865220576 -0400
  File: ‘file3’
Access: 2018-08-11 23:55:20.866220542 -0400
  File: ‘file4’
Access: 2018-08-11 23:55:20.867220508 -0400
    
por 12.08.2018 / 05:19