Imprime padrões incomparáveis, usando grep com padrões de arquivo

13

patterns.txt:

"BananaOpinion"
"ExitWarning"
"SomeMessage"
"Help"
"Introduction"
"MessageToUser"

Strings.xml

<string name="Introduction">One day there was an apple that went to the market.</string>
<string name="BananaOpinion">Bananas are great!</string>
<string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>

Resultado esperado:

"ExitWarning"
"SomeMessage"
"Help" 

Como imprimo os termos em patterns.txt que não são encontrados em Strings.xml ? Eu posso imprimir as linhas combinadas / inigualadas em Strings.xml , mas como eu imprimo os padrões sem correspondência? Estou usando o ggrep (GNU grep) versão 2.21, mas estou aberto a outras ferramentas. Desculpas se esta for uma duplicata de outra questão que não consegui encontrar.

    
por Nate Cook 07.04.2015 / 01:29

5 respostas

21

Você pode usar grep -o para imprimir apenas a parte correspondente e usar o resultado como padrões para um segundo grep -v no arquivo patterns.txt original:

grep -oFf patterns.txt Strings.xml | grep -vFf - patterns.txt

No entanto, neste caso em particular, você também pode usar join + sort :

join -t\" -v1 -j2 -o 1.1 1.2 1.3 <(sort -t\" -k2 patterns.txt) <(sort -t\" -k2 strings.xml)
    
por 07.04.2015 / 01:38
5

A melhor abordagem é provavelmente o que @don_crissti sugeriu, então aqui está uma variação sobre o mesmo tema:

$ grep -vf <(grep -Po 'name=\K.+?"' Strings.xml) patterns.txt
"ExitWarning"
"SomeMessage"
"Help"

Esta é basicamente a abordagem inversa de @ don_crissti. Ele usa grep com expressões regulares compatíveis com Perl ( -P ) e a opção -o para imprimir apenas a parte correspondente da linha. Em seguida, a regex procura name= e descarta ( \K ) e, em seguida, procura um ou mais caracteres até o primeiro " ( .+?" ). Isso resulta na lista de padrões presentes no arquivo String.txt , que é então passado como entrada para um grep reverso ( grep -v ) usando processo de substituição ( <(command) ).

    
por 07.04.2015 / 01:49
2

Eu usaria cut , provavelmente. Ou seja, se, ao que parece, você souber onde esperar a string citada que está procurando.

Se eu fizer:

{   cut  -sd\" -f2 |
    grep -vFf- pat
}   <<\IN
#   <string name="Introduction">One day there was an apple that went to the market.</string>
#   <string name="BananaOpinion">Bananas are great!</string>
#   <string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>
IN

... depois de salvar minha própria cópia do seu exemplo patterns.txt in pat e executar o comando acima, a saída é:

"ExitWarning"
"SomeMessage"
"Help"

cut imprime para stdout apenas o segundo " double-quote -d elimited -f ield para cada linha de entrada combinada pelo delimitador e -s pressiona todos os outros.

O que cut realmente imprime em grep é:

Introduction
BananaOpinion
MessageToUser

grep pesquisa seu operando de arquivo nomeado para as linhas que -v não correspondem às sequências -F ixed em seu - padrão stdin -f ile.

Se você puder confiar no segundo campo " -delimited como o que deve corresponder, então definitivamente haverá uma otimização sobre o modo grep -P erl combinando apenas sequências -F ixed e apenas pequenas porções deles porque cut faz o trabalho pesado - e faz isso rápido .

    
por 07.04.2015 / 03:26
1
for p in $(cat patterns.txt); do if ! grep $p strings.xml &>/dev/null; then echo $p; fi; done

é fácil de entender, mas tem o tempo de inatividade de vários processos do grep, um para cada linha no patterns.txt.

    
por 23.02.2018 / 16:16
0

outra maneira é colocar patterns.txt e Strings.xml em uma lista e encontrar linhas exclusivas

cat patterns.txt Strings.xml | grep -oFf patterns.txt | sort | uniq -u

explicação:

cat patterns.txt Strings.xml coloca tudo em uma lista. grep -oFf patterns.txt remove o lixo em cada linha. sort auto-explicativo. classificar todas as linhas. uniq -u imprime somente linhas exclusivas.

    
por 21.02.2018 / 16:44

Tags