Como encontrar uma string de várias linhas no shell script?

4

Eu quero encontrar a string

Time series prediction with ensemble models

em um pdf fle usando shell script.Estou usando pdftotext "$file" - | grep "$string" .where $file é o nome do arquivo pdf e $string é a string acima.Ela pode descobrir a linha se a cadeia inteira contiver em uma linha .mas não consegue descobrir a linha como:

Time series prediction with 
ensemble models

como posso resolvê-lo. Sou novo no linux. então a explicação em detalhe é apreciada. Agradecemos antecipadamente.

    
por Mousumi 11.09.2015 / 07:59

3 respostas

4

Uma maneira possível pode ser substituir grep by pcregrep (disponível no repositório 'universe'), que suporta correspondências multilinhas e, em vez de pesquisar a cadeia literal

Time series prediction with ensemble models

pesquise em vez disso pela expressão regular compatível com perl (PCRE)

Time\s+series\s+prediction\s+with\s+ensemble\s+models

onde \s+ significa um ou mais caracteres em branco (incluindo novas linhas). Usando os recursos internos de substituição de strings do bash shell para executar a última etapa

pdftotext "$file" - | pcregrep -M "${string// /\s+}"

Se você não puder usar pcregrep , poderá obter a saída desejada usando grep simples com a opção -z : isso diz a grep para considerar as "linhas" de entrada a serem delimitadas por NUL caracteres em vez de novas linhas - neste caso, efetivamente fazendo com que ele trate toda a entrada como uma única linha. Por exemplo, se você quiser apenas imprimir as correspondências (sem contexto)

pdftotext "$file" - | grep -zPo "${string// /\s+}"
    
por steeldriver 11.09.2015 / 09:18
1

Com o Python, muito pode ser feito ...

Se eu olhar para ele novamente mais tarde, provavelmente serei capaz de fazer alguma otimização, mas nos meus testes, o script abaixo faz o trabalho.

Testado em um arquivo:

Monkey eats banana since he ran out of peanuts 
Monkey
eats banana since he ran 
out of peanuts 
really, Monkey eats banana since 
he ran out of peanuts 
A lot of useless text here…
Have to add some lines for the sake of the test.
Monkey eats banana since he ran out of peanuts 

procurando por uma string "Macaco come banana desde que ele ficou sem amendoim", ele produz:

Found matches
--------------------
[line 1]
Monkey eats banana since he ran out of peanuts
[line 2]
Monkey
eats banana since he ran
out of peanuts
[line 5]
Monkey eats banana since
he ran out of peanuts
[line 9]
Monkey eats banana since he ran out of peanuts

O script

#!/usr/bin/env python3
import subprocess
import sys

f = sys.argv[1]; string = sys.argv[2]

# convert to .txt with your suggestion
subprocess.call(["pdftotext", f])
# read the converted file
text = open(f.replace(".pdf", ".txt")).read()
# editing the file a bit for searching options / define th length of the searched string
subtext = text.replace("\n", " "); size = len(string)
# in a while loop, find the matching string and set the last found index as a start for the next match
matches = []; start = 0
while True:
    match = subtext.find(string, start)
    if match == -1:
        break
    else:
        matches.append(match)
    start = match+1

print("Found matches\n"+20*"-")
for m in matches:
    # print the found matches, replacing the edited- in spaces by (possibly) original \n
    print("[line "+str(text[:m].count("\n")+1)+"]\n"+text[m:m+size].strip())

Para usá-lo:

  1. copie o script em um arquivo vazio, salve-o como search_pdf.py
  2. Execute-o pelo comando:

    python3 /path/to/search_pdf.py /path/to/file.pdf string_to_look_for
    

Não é necessário mencionar que você precisa usar aspas se o caminho ou a string pesquisada incluir espaços:

python3 '/path to/search_pdf.py' '/path to/file.pdf' 'string to look for'
    
por Jacob Vlijm 11.09.2015 / 09:19
0

Outra abordagem sugerida pela steeldriver nos comentários é substituir todas as quebras de linha por espaços, convertendo a saída de pdftotext em uma linha longa e pesquisando:

string="Time series prediction with ensemble models"
pdftotext "$file" - | tr '\n' ' ' | grep -o "$string"

Eu adicionei o -o para fazer grep imprimir apenas a parte correspondente da linha. Sem isso, você teria todo o conteúdo do arquivo impresso.

Outra abordagem seria usar a opção grep do -z , que diz para usar \n em vez de %code% para definir linhas. Isso significa que a entrada inteira será tratada como uma única "linha" e você poderá usar expressões regulares compatíveis ou com extensão Perl para corresponder a ela:

$ printf 'foo\nbar\nbaz\n' | grep -oPz 'foo\nbar'
foo
bar

Isso, no entanto, não ajudará, a menos que você saiba de antemão como a string foi dividida em várias linhas.

    
por terdon 11.09.2015 / 12:55