Stampa motivi senza eguali, usando grep con motivi da file


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>

Uscita prevista:

"ExitWarning"
"SomeMessage"
"Help" 

Come si stampano i termini in patterns.txtcui non si trovano Strings.xml? Posso stampare i corrispondenti / ineguagliate linee a Strings.xml, ma come faccio a stampare le impareggiabili modelli ? Sto usando ggrep (GNU grep) versione 2.21, ma sono aperto ad altri strumenti. Mi scuso se questo è un duplicato di un'altra domanda che non sono riuscito a trovare.

Risposte:


25

È possibile utilizzare grep -oper stampare solo la parte corrispondente e utilizzare il risultato come motivi per un secondo grep -vsul patterns.txtfile originale :

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

Sebbene in questo caso particolare potresti anche usare join+ sort:

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

questo è abbastanza elegante .. intelligente!
XXL

Se hai più file di input (ad es. Strings1.xmlE Strings2.xml), avrai bisogno anche del -hflag al primo grep.
Jayhendren,

@jayhendren - sì, ma non tutti grepsupportano questa opzione. Se disponi di più file di input, non vedo perché non potresti semplicemente cattutti e reindirizzare il risultato grep.
don_crissti,

5

L'approccio migliore è probabilmente quello che ha suggerito @don_crissti, quindi ecco una variazione sullo stesso tema:

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

Questo in pratica è l'inverso dell'approccio di @ don_crissti. Utilizza grep con le espressioni regolari compatibili Perl ( -P) e l' -oopzione per stampare solo la parte corrispondente della riga. Quindi, il regex lo cerca name=e lo scarta ( \K), quindi cerca uno o più caratteri fino al primo "( .+?"). Questo risulta nella lista dei pattern presenti nel String.txtfile che viene poi passato come input a un grep ( grep -v) inverso usando process substitution ( <(command)).


2

Vorrei usare cut, probabilmente. Cioè, se, come sembra, sai dove aspettarti la stringa tra virgolette che stai cercando.

Se lo faccio:

{   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

... dopo aver salvato la mia copia del vostro esempio patterns.txtin pated eseguendo il comando sopra l'output è:

"ExitWarning"
"SomeMessage"
"Help"

cutstampa solo stdout della seconda ield tra "virgolette -ddoppie -fper ogni riga di input corrispondente al delimitatore e -ssostituisce tutte le altre.

Ciò che cuteffettivamente stampa grepè:

Introduction
BananaOpinion
MessageToUser

grepcerca nel suo operando di file denominato le righe che -vnon corrispondono alle -Fstringhe ixed nel suo -modello stdin -file.

Se puoi fare affidamento sul secondo "campo delimitato come quello da abbinare, allora sarà sicuramente un'ottimizzazione rispetto alla grep -Pmodalità erl semplicemente abbinando le -Fstringhe ixed e solo minuscole porzioni perché cutfa il sollevamento pesante - e lo fa velocemente .


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

è facile da capire ma ha il tempo morto di generare più processi grep, uno per ogni riga in patterns.txt.


0

un altro modo è quello di mettere patterns.txt e Strings.xml in un elenco e trovare righe uniche

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

spiegazione:

cat patterns.txt Strings.xmlmette tutto in un elenco. grep -oFf patterns.txtrimuove la spazzatura su ogni riga. sortauto-esplicativo. ordina tutte le righe. uniq -ustampa solo linee uniche.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.