¿Cómo eliminar las líneas que aparecen en el archivo B de otro archivo A?

Tengo un archivo grande A (que consiste en correos electrónicos), una línea para cada correo. También tengo otro archivo B que contiene otro conjunto de correos.

¿Qué comando usaría para eliminar todas las direcciones que aparecen en el archivo B del archivo A.

Entonces, si el archivo A contiene:

A B C 

y el archivo B contenía:

 BD E 

Entonces, el archivo A debe quedar con:

 A C 

Ahora sé que esta es una pregunta que podría haberse formulado con más frecuencia, pero solo encontré un comando en línea que me dio un error con un delimitador incorrecto.

¡Cualquier ayuda sería muy apreciada! Alguien seguramente tendrá una idea inteligente, pero yo no soy el experto en proyectiles.

 comm -23 file1 file2 

-23 suprime las líneas que están en ambos archivos, o solo en el archivo 2. Los archivos tienen que estar ordenados (están en su ejemplo), pero si no, pídalos por sort primero …

Vea la página de manual aquí

grep -Fvxf

  • funciona en archivos no ordenados
  • mantiene el orden
  • es POSIX

Ejemplo:

 cat < A b 1 a 0 01 b 1 EOF cat < B 0 1 EOF grep -Fvxf BA 

Salida:

 b a 01 b 

Explicación:

  • -F : use cadenas literales en lugar del BRE predeterminado
  • -x : solo considera las coincidencias que coinciden con toda la línea
  • -v : impresión no coincidente
  • -f file : toma patrones del archivo dado

Este método es más lento en los archivos preordenados que en otros métodos, ya que es más general. Si la velocidad también importa, consulte: ¿ Forma rápida de encontrar líneas en un archivo que no están en otro?

Ver también: https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another

¡awk al rescate!

Esta solución no requiere entradas ordenadas. Primero debe proporcionar el archivo B.

 awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA 

devoluciones

 A C 

¿Como funciona?

NR==FNR{a[$0];next} idioma es para almacenar el primer archivo en una matriz asociativa como claves para una prueba posterior “contiene”.

NR==FNR está comprobando si estamos escaneando el primer archivo, donde el contador de línea global (NR) es igual al contador de línea de archivo actual (FNR).

a[$0] agrega la línea actual a la matriz asociativa como clave, tenga en cuenta que esto se comporta como un conjunto, donde no habrá ningún valor duplicado (claves)

!($0 in a) ahora estamos en el (los) siguiente (s) archivo (s), in es una prueba contiene, aquí estamos verificando si la línea actual está en el conjunto que llenamos en el primer paso desde el primer archivo ! niega la condición. Lo que falta aquí es la acción, que por defecto es {print} y generalmente no está escrita explícitamente.

Tenga en cuenta que esto ahora se puede utilizar para eliminar las palabras incluidas en la lista negra.

 $ awk '...' badwords allwords > goodwords 

con un ligero cambio puede limpiar múltiples listas y crear versiones limpias.

 $ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ... 

Otra forma de hacer lo mismo (también requiere una entrada ordenada):

 join -v 1 fileA fileB 

En Bash, si los archivos no están ordenados previamente:

 join -v 1 <(sort fileA) <(sort fileB) 

Puede hacerlo a menos que sus archivos estén ordenados

 diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a 

--new-line-format es para las líneas que están en el archivo b pero no en un --old-.. es para las líneas que están en el archivo a, pero no en b – sin --unchanged-.. es para las líneas que están en ambos . %L hace para que la línea se imprima exactamente.

 man diff 

para más detalles

Este refinamiento de la buena respuesta de @karakfa puede ser notablemente más rápido para archivos muy grandes. Al igual que con esa respuesta, ninguno de los archivos debe ser ordenado, pero la velocidad está asegurada gracias a las matrices asociativas de awk. Solo el archivo de búsqueda se guarda en la memoria.

Esta formulación también permite la posibilidad de que solo un campo particular ($ N) en el archivo de entrada se use en la comparación.

 # Print lines in the input unless the value in column $N # appears in a lookup file, $LOOKUP; # if $N is 0, then the entire line is used for comparison. awk -v N=$N -v lookup="$LOOKUP" ' BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } } !($N in dictionary) {print}' 

(Otra ventaja de este enfoque es que es fácil modificar el criterio de comparación, por ejemplo, para recortar el espacio en blanco inicial y final).

Puedes usar Python:

 python -c ' lines_to_remove = set() with open("file B", "r") as f: for line in f.readlines(): lines_to_remove.add(line.strip()) with open("file A", "r") as f: for line in [line.strip() for line in f.readlines()]: if line not in lines_to_remove: print(line) ' 

Puede usar – diff fileA fileB | grep "^>" | cut -c3- > fileA diff fileA fileB | grep "^>" | cut -c3- > fileA

Esto funcionará para archivos que no están clasificados también.