exibe o conteúdo do arquivo desde o início até um padrão de várias linhas

4

Como posso exibir o conteúdo do arquivo desde o início até um padrão de várias linhas sem incluir o próprio padrão?

Por exemplo, se eu tivesse um arquivo de texto como este:

cat
dog
fox
cow
dove
bird
bunny
gnu
hen
dove
bird
buffalo

e se meu padrão fosse este:

dove
bird
bunny

o que eu gostaria de obter seria:

cat
dog
fox
cow

Meu arquivo real é enorme, por isso, se houver várias maneiras de conseguir isso, prefiro maneiras mais rápidas.

Além disso, eu fiz uma pergunta semelhante relacionada a isso agora, mas é diferente, então não marque isso como duplicado só por causa disso!

    
por stacko 21.06.2017 / 20:10

3 respostas

1

Você pode manipular a linha de entrada com sed e encadear a correspondência de padrão de várias linhas:

/pat1/ { N; N; ...; /pat2\npat3\n.../q }

Então, no seu exemplo, isso seria, por exemplo:

sed -n '/^dove$/ { N; N; /\nbird\nbunny$/q; }; p' infile

Saída:

cat
dog
fox
cow
    
por 21.06.2017 / 21:31
1

Aqui está uma abordagem sed alternativa, que usa ramificação para manter um buffer de 3 linhas no espaço padrão e testá-lo no padrão de múltiplas linhas, parando quando encontrado:

sed -n '
  :a
  $q
  N
  /dove\nbird\nbunny/q
  3,$ {
    P
    D
  }
  ba
' file

Com o GNU sed, você pode usar o comando Q para sair sem imprimir o espaço padrão atual, além de permitir uma sintaxe mais livre, por exemplo,

sed -e :a -e '$Q' -e 'N;/dove\nbird\nbunny/Q' -e '3,${P;D}' -e 'ba' file

ou

sed ':a; $Q; N; /dove\nbird\nbunny/Q; 3,${P;D}; ba' file
    
por 21.06.2017 / 21:32
0

Aqui está um pouco de hack do Python para fazer isso.

Código:

# !/usr/bin/python
import sys
with open(sys.argv[2], 'rU') as f:
    patterns = f.readlines()

result = None
with open(sys.argv[3], 'rU') as f:
    last_match = 0
    for i, line in enumerate(f):
        if line != patterns[last_match]:
            last_match = 0
        else:
            last_match += 1
            if last_match == len(patterns):
                result = i + 1 - len(patterns)
                break

if result != None:
    if sys.argv[1] == 'tail':
        print("tail -n+%d %s" % (result+1, sys.argv[3]))
    else:
        print("head -n%d %s" % (result, sys.argv[3]))

Executar

Para produzir até o padrão:

'python split_on_pattern.py head pattern_file data_file'

Para gerar o padrão em:

'python split_on_pattern.py tail pattern_file data_file'
    
por 21.06.2017 / 21:12