Tengo dos archivos. estoy tratando de eliminar cualquier línea en el archivo2 cuando coinciden con los valores encontrados en el archivo1. Un archivo tiene un listado así:
Archivo 1
ZNI008 ZNI009 ZNI010 ZNI011 ZNI012
… más de 19463 líneas
El segundo archivo incluye líneas que coinciden con los elementos enumerados en el primero: Archivo2
copy /Y \\server\foldername\version\20050001_ZNI008_162635.xml \\server\foldername\version\folder\ copy /Y \\server\foldername\version\20050001_ZNI010_162635.xml \\server\foldername\version\folder\ copy /Y \\server\foldername\version\20050001_ZNI012_162635.xml \\server\foldername\version\folder\ copy /Y \\server\foldername\version\20050001_ZNI009_162635.xml \\server\foldername\version\folder\
… continúa listado hasta la línea 51360
Lo que he probado hasta ahora:
grep -v -i -f file1.txt file2.txt > f3.txt
no produce ninguna salida a f3.txt
ni elimina ninguna línea. Lo verifiqué corriendo
wc -l file2.txt
y el resultado es
51360 file2.txt
Creo que la razón es que no hay coincidencias exactas. Cuando corro lo siguiente no muestra nada.
comm -1 -2 file1.txt file2.txt
Corriendo
( tr '\0' '\n' < file1.txt; tr '\0' '\n' < file2.txt ) | sort | uniq -c | egrep -v '^ +1'
muestra solo una coincidencia, aunque puedo ver claramente que hay más de una coincidencia.
Alternativamente, al colocar todos los datos en un solo archivo y ejecutar lo siguiente:
grep -Ev "$(cat file1.txt)" 1>LinesRemoved.log
dice que el argumento tiene demasiadas líneas para procesar.
Necesito eliminar las líneas que coinciden con los elementos en el archivo1 del archivo2.
También estoy intentando esto en python: `
#!/usr/bin/python s = set() # load each line of file1 into memory as elements of a set, 's' f1 = open("file1.txt", "r") for line in f1: s.add(line.strip()) f1.close() # open file2 and split each line on "_" separator, # second field contains the value ZNIxxx f2 = open("file2.txt", "r") for line in f2: if line[0:4] == "copy": fields = line.split("_") # check if the field exists in the set 's' if fields[1] not in s: match = line else: match = 0 else: if match: print match, line,
`
no está funcionando bien … como estoy recibiendo ‘Traceback (última llamada más reciente): archivo “./test.py”, línea 14, en? si los campos [1] no están en s: IndexError: índice de lista fuera de rango ‘
Qué pasa:
grep -F -v -f file1 file2 > file3
esto está usando Bash y GNU sed debido al interruptor -i
cp file2 file3 while read -r; do sed -i "/$REPLY/d" file3 done < file1
Seguramente hay una mejor manera, pero aquí hay un hack- -i
: D
cp file2 file3 while read -r; do (rm file3; sed "/$REPLY/d" > file3) < file3 done < file1
esto explota el orden de evaluación de la concha
bien, supongo que la forma correcta con esta idea es usando ed
. Esto debería ser POSIX también.
cp file2 file3 while read -r line; do ed file3 <
En cualquier caso, grep
parece ser la herramienta adecuada para el trabajo.
La respuesta de @byrondrossos debería funcionar bien para ti;)
Esto es cierto feo pero funciona. Sin embargo, la ruta debe ser la misma para todas las partes (excepto, por supuesto, la parte ZNI ###). Se eliminan todos, excepto el ### ZNI de la ruta, por lo que el comando grep -vf puede ejecutarse correctamente en los archivos ordenados.
Primero convierta “testfile2” a “testfileconverted” para mostrar solo el ZNI ###
cat /testfile2 | sed 's:^.*_ZNI:ZNI:g' | sed 's:_.*::g' > /testfileconverted
Segundo, use el grep inverso del archivo convertido en comparación con el “testfile1” y agregue la salida reformateada a “testfile3”
bash -c 'grep -vf <(sort /testfileconverted) <(sort /testfile1)' | sed "s:^:\copy /Y \\\|server\\\foldername\\\version\\\20050001_:g" | sed "s:$:_162635\.xml \\\|server\\\foldername\\\version\\\folder\\\:g" | sed "s:|:\\\:g" > /testfile3
Me gusta más la solución grep de byrondrossos, pero aquí hay otra opción:
sed $(awk '{printf("-e /%s/d ", $1)}' file1) file2 > file3