Imprima patrones sin igual, utilizando grep con patrones del archivo

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>

Rendimiento esperado:

"ExitWarning"
"SomeMessage"
"Help" 

¿Cómo imprimo los términos patterns.txtque no se encuentran en Strings.xml? Puedo imprimir los emparejados / incomparables líneas en Strings.xml, pero ¿cómo puedo imprimir los incomparables patrones ? Estoy usando ggrep (GNU grep) versión 2.21, pero estoy abierto a otras herramientas. Disculpas si este es un duplicado de otra pregunta que no pude encontrar.

Nate Cook
fuente

Respuestas:

25

Puede usar grep -opara imprimir solo la parte coincidente y usar el resultado como patrones por un segundo grep -ven el patterns.txtarchivo original :

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

Aunque en este caso particular también podría usar join+ sort:

join -t\" -v1 -j2 -o 1.1 1.2 1.3 <(sort -t\" -k2 patterns.txt) <(sort -t\" -k2 strings.xml)
don_crissti
fuente
esto es bastante elegante ... inteligente!
XXL
Si tiene varios archivos de entrada (por ejemplo, Strings1.xmly Strings2.xml), también necesitará el -hindicador en el primer grep.
jayhendren
@jayhendren: sí, pero no todos grepadmiten esa opción. Si tiene varios archivos de entrada, no entiendo por qué no podría simplemente cateliminarlos todos y canalizar el resultado grep.
don_crissti
5

El mejor enfoque es probablemente lo que sugirió @don_crissti, así que aquí hay una variación sobre el mismo tema:

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

Esto es básicamente lo contrario del enfoque de @ don_crissti. Utiliza grep con Expresiones regulares compatibles con Perl ( -P) y el -ointerruptor para imprimir solo la parte correspondiente de la línea. Luego, la expresión regular lo busca name=y lo descarta ( \K), y luego busca uno o más caracteres hasta el primero "( .+?"). Esto da como resultado la lista de patrones presentes en el String.txtarchivo que luego se pasa como entrada a un grep inverso ( grep -v) usando la sustitución de proceso ( <(command)).

terdon
fuente
2

Yo usaría cut, probablemente. Es decir, si, como parece, sabe dónde esperar la cadena citada que está buscando.

Si lo hago:

{   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

... después de salvar mi propia copia de su ejemplo patterns.txten paty ejecutar el comando anterior, la salida es:

"ExitWarning"
"SomeMessage"
"Help"

cutimprime en stdout solo el segundo campo eliminado de "comillas -ddobles -fpara cada línea de entrada -sdelimitadora y presiona todas las demás.

Lo que cutrealmente imprime grepes:

Introduction
BananaOpinion
MessageToUser

grepbusca en su operando de archivo nombrado las líneas que -vno coinciden con las -Fcadenas ixed en su -patrón de patrón estándar -f.

Si puede confiar en el segundo "campo delimitado como el que debe coincidir, entonces definitivamente será una optimización sobre el grep -Pmodo erl simplemente haciendo coincidir las -Fcadenas ixed y solo pequeñas porciones de ellas porque cuthace el trabajo pesado, y lo hace rápido .

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

es fácil de entender pero tiene el tiempo de inactividad de generar múltiples procesos grep, uno para cada línea en patterns.txt.

usuario277493
fuente
0

otra forma es poner patterns.txt y Strings.xml en una lista y encontrar filas únicas

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

explicación:

cat patterns.txt Strings.xmlpone todo en una lista. grep -oFf patterns.txtelimina la basura en cada línea. sortAutoexplicativo. Ordenar todas las líneas. uniq -uimprime solo líneas únicas.

erik80
fuente