Imprima padrões incomparáveis, usando grep com padrões do arquivo


15

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>

Saída esperada:

"ExitWarning"
"SomeMessage"
"Help" 

Como imprimo os termos em patterns.txtque não são encontrados Strings.xml? Eu posso imprimir os combinados / incomparáveis linhas em Strings.xml, mas como faço para imprimir as inigualáveis padrões ? Estou usando o ggrep (GNU grep) versão 2.21, mas estou aberto a outras ferramentas. Desculpas se esta é uma duplicata de outra pergunta que não consegui encontrar.

Respostas:


25

Você pode usar grep -opara imprimir apenas a parte correspondente e usar o resultado como padrões por um segundo grep -vno patterns.txtarquivo original :

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

Embora, neste caso em particular, você também possa usar join+ sort:

join -t\" -v1 -j2 -o 1.1 1.2 1.3 <(sort -t\" -k2 patterns.txt) <(sort -t\" -k2 strings.xml)

isso é bem elegante .. esperto!
XXL

Se você tiver vários arquivos de entrada (por exemplo, Strings1.xmle Strings2.xml), também precisará da -hbandeira no primeiro grep.
jayhendren

@ Jayhendren - sim, mas nem todos greps suportam essa opção. Se você possui vários arquivos de entrada, não vejo por que você não pode simplesmente cattodos eles e canalizar o resultado grep.
don_crissti

5

A melhor abordagem é provavelmente o que o @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"

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


2

Eu usaria cut, provavelmente. Ou seja, se, como parece, você sabe onde esperar a sequência de caracteres 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 a minha própria cópia de seu exemplo patterns.txtno pate executar o comando acima, a saída é:

"ExitWarning"
"SomeMessage"
"Help"

cutimprime em stdout apenas o segundo campo elimitado por "aspas -dduplas -fpara cada linha de entrada correspondente ao delimitador e -spressiona todas as outras.

O que cutrealmente imprime grepé:

Introduction
BananaOpinion
MessageToUser

grepprocura no seu operando de arquivo nomeado por linhas que -vnão correspondam às -Fseqüências ixed em seu arquivo -padrão stdin -f.

Se você pode confiar no segundo "campo delimitado como o que corresponder, será definitivamente uma otimização no grep -Pmodo erl, apenas combinando -Fstrings ixadas e apenas pequenas porções delas porque cutfaz o trabalho pesado - e rápido .


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 gerar vários processos grep, um para cada linha em patterns.txt.


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.xmlcoloca tudo em uma lista. grep -oFf patterns.txtremove o lixo em cada linha. sortauto-explicativo. classifique todas as linhas. uniq -uimprime apenas linhas exclusivas.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.