Como imprimir o padrão introduzido que não possui linhas correspondentes?

5

Eu tenho este comando grep para encontrar arquivos com padrão de correspondência.

grep -oiE 'pattern1|pattern2|pattern3|pattern4' *pattern_in_a_filename* | sort -u

Saída:

file_one:pattern1
file_two:pattern2
file_two:pattern3

O que eu quero é mostrar o pattern4 dizendo que não está sendo encontrado como este exemplo:

file_one:pattern1
file_two:pattern2
file_two:pattern3
pattern4 not found

Eu estou fazendo milhares de milhares de padrões e isso tem que ser feito o mais rápido possível, porque estes são dados cruciais necessários em nossas operações.

    
por WashichawbachaW 17.10.2017 / 11:10

4 respostas

2

Veja um script sh que produz os resultados de que você precisa.

#!/bin/sh

grep -f /path/to/patterns.txt /path/to/*_856_2017* | sort -u > /path/to/foundFiles.txt 

while read -r LINE
do
    grep -F "$LINE" /path/to/foundFiles.txt
    if [ $? -eq 1 ]
    then
        echo "$LINE" not found
    fi
done < /path/to/patterns.txt

Neste script, presumo que você envie os resultados de seu grep para o arquivo found.txt e armazene seus padrões no arquivo /path/to/foundFiles.txt .

Como você pode ver, o grep no loop produzirá o mesmo conteúdo do arquivo found.txt ao adicionar "$pattern" not found para os que faltam.

Eu também criei uma segunda abordagem para o seu caso:

#!/bin/sh

grep -f /path/to/patterns.txt /path/to/*_856_2017* |
    sort -u > /path/to/foundFiles.txt

comm -23 /path/to/patterns.txt /path/to/foundFiles.txt |
    xargs -L 1 -I {} echo {} not found > /path/to/notFoundFiles.txt

cat /path/to/foundFiles.txt /path/to/notFoundFiles.txt > /path/to/finalList.txt

Nesse caso, patterns.txt precisa estar classificado para comm para funcionar.

O comando comm compara os dois arquivos que retornam as linhas presentes apenas em patterns.txt ( -23 parameter), que é a lista de padrões não encontrados por grep .

Em seguida, xargs pega cada linha ( -L 1 ) e ecoa a linha ( {} ) com "não encontrado" anexada a ela. O resultado de xargs é redirecionado para o arquivo notFoundFiles.txt .

Finalmente, você simplesmente concatena foundFiles.txt e notFoundFiles.txt em finalList.txt .

    
por 17.10.2017 / 14:32
6

it has to be done as quick as possible

Deseja fazer as coisas o mais rápido possível?

Descubra processamento paralelo e aplique a seguinte solução parallel do GNU:

O caminho certo começa colocando todos os seus padrões em arquivo, digamos patterns.txt .

O trabalho crucial:

cat patterns.txt | parallel -j 0 --no-notice 'grep -Hoi {} /path/to/files/* || echo "{} not found"' | sort -u
  • -j N - Número de jobslots. Execute até N jobs em paralelo. 0 significa o maior número possível. O padrão é 100%, o qual será executado             um trabalho por núcleo da CPU.

O comando acima irá procurar por padrão de patterns.txt dentro de todos os arquivos em paralelo.

Eu fiz um teste com apenas 2 núcleos de CPU com uma lista de padrões e alguns arquivos csv de 641 Mb cada. E obtenho um aumento de velocidade de 470% em comparação com o processamento consecutivo.
Quanto mais núcleos de CPU o seu computador tiver, mais desempenho de velocidade de tempo você alcançará.

Faça suas conclusões ...

link

    
por 17.10.2017 / 15:54
5

A ferramenta grep pesquisa arquivos por padrões. Isso significa que o padrão é a entrada e o arquivo é a saída. E isso significa que tudo que você pode encontrar com o grep são arquivos, mas não padrões.

Para encontrar esses arquivos, que não contêm um padrão de correspondência, você precisa inverter a pesquisa com -v . Isso requer duas chamadas.

Exemplo:

$ echo a > xa
$ echo ab > xab
$ echo c > xc
$ { grep -oiE 'a|b' x*; grep -vl -E 'a|b' x*; } | sort -u
xa:a
xab:a
xab:b
xc

Para encontrar esses padrões, que não correspondem, você precisa tornar seus padrões a entrada e o resultado da pesquisa o padrão. A lista de correspondências se torna o padrão e o padrão torna-se os dados, nos quais você precisa pesquisar.

Vamos supor que esse pode ser o padrão dos arquivos do exemplo anterior.

$ pattern='a|b|d'

Em seguida, isso armazena a lista de padrões correspondentes em uma matriz:

$ found=($(grep -hoiE "$pattern" x* | sort -u))

E isso converte a matriz no novo padrão:

$ new_pattern="$(IFS='|' ; echo "${found[*]}")"

E isso converte o padrão original em dados:

$ data="${pattern//|/$'\n'}"

Em seguida, esta é a lista de padrões que não correspondem:

$ grep -viE "$new_pattern" <<< "$data"
d
    
por 17.10.2017 / 13:38
3

Aqui está uma maneira de alcançar o que você espera. Como você afirmou que tem milhares de padrões, presumo que você alimente padrões de um arquivo, então é muito melhor do que passar padrões direto para grep . O comando é o seguinte.

grep -oif ../patt_file file* && 
    printf "%s Not Found.\n" $(grep -vFxf <(grep -oihf ../patt_file file*) \
    <(< ../patt_file))

Para evitar a correspondência dos padrões do arquivo patt_file , você precisa movê-lo para um diretório diferente daquele onde sua entrada infiles* está lá.

    
por 17.10.2017 / 13:31