Tengo 3 archivos de texto con algunas identificaciones únicas y quiero conservar solo identificaciones únicas en cada archivo de texto. Digamos que hay 3 archivos (A, B y C). Si aparece un ID de "abc" en A y B, es necesario eliminarlo de ambos archivos.
Los archivos están ordenados y tienen un tamaño inferior a 1 MB y los ID son caracteres alpanuméricos. Además, dentro de cada archivo, no hay duplicados.
¿Hay alguna manera de hacer esto simplemente usando herramientas de línea de comandos en Linux o Mac? Inicialmente estaba pensando en escribir un código, pero quería preguntar primero. ¡Gracias!
Respuesta1
Supuestos:
- los archivos de texto tienen un único ID por línea
- cada línea solo contiene una identificación y ningún otro texto
- los ID no se repiten dentro de un archivo
- está bien reordenar el archivo de salida (ordenarlo)
- la eficiencia de ejecución no es importante
- Las identificaciones son alfanuméricas
$ cat A B B C C | sort | uniq -u >A.uniq
$ cat B A A C C | sort | uniq -u >B.uniq
$ cat C A A B B | sort | uniq -u >C.uniq
$ mv A.uniq A
$ mv B.uniq B
$ mv C.uniq C
El comando 'cat' concatena los archivos listados. El primer archivo es el que quiero eliminar de duplicados. Los siguientes archivos son los posibles duplicados que quiero eliminar. Agrego dos copias de cada uno de estos archivos para garantizar que estén duplicados y serán eliminados.
A continuación, "ordeno" estos archivos alfabéticamente. Esto da como resultado que cualquier ID duplicado se encuentre en líneas vecinas en la salida ordenada.
El comando 'uniq' con la opción '-u' solo genera líneas que son únicas. Si dos o más ID iguales aparecen en líneas vecinas en la entrada, no se genera nada.
El '>' escribe la salida en un nuevo archivo llamado 'A.uniq'
Si quisieras hacer lo contrario y generar una lista de todos los ID que están duplicados en los 3 archivos, podrías hacer algo como:
$ cat A B C | sort | uniq -d >duplicates
El comando 'uniq' con el indicador '-d' solo genera una línea si se repite dos o más veces en la entrada.
Respuesta2
Gracias por la distracción. Se me ocurrió el siguiente guión (documentado):
#! /bin/bash
SOURCEFILES="./existing/list1.txt ./existing/list2.txt ./existing/list3.txt"
# First find a list of duplicate files. We do this by catting all files and finding where there are lines that are not unique
# $DUPLICATES will be a space seperated list of duplicate IDs
DUPLICATES=$( cat $SOURCEFILES | sort | uniq -d )
echo "Duplicates Found for removal: " $DUPLICATES
# Convert list of duplicates into a pipe seperated list
# Commented out version assumes all ID's are all the same length, so it would break if one is ABC and another is ABCD
#DUPLICATES=$( echo $DUPLICATES | tr ' ' '|' )
# This version translates the duplicate REGEX to say that each line is complete
# ^ means start of line and $ means end of line.
for each in $DUPLICATES
do
DUPLIST="$DUPLIST^$each$|"
done
# Remove trailing "|" from DUPLIST
DUPLICATES=$( echo ${DUPLIST::-1} )
# Go through each file, removing duplicates
for each in $SOURCEFILES
do
mv $each $each.old
egrep -v "$DUPLICATES" < $each.old > $each
done