Estoy seguro de que una vez encontré un comando Unix que podía imprimir las líneas comunes de dos o más archivos, ¿alguien sabe su nombre? Fue mucho más simple que diff
.
unix
shell
command-line
demasiado php
fuente
fuente
comm
requiere archivos de entrada ordenados. Si quieres solo línea por línea común, es genial. Pero si quieres lo que yo llamaría "anti-diff",comm
no hace el trabajo.pr-123-xy-45
y el archivo2 contieneec11_orop_pr-123-xy-45.gz
. Necesito el archivo 3 que contieneec11_orop_pr-123-xy-45.gz
Respuestas:
El comando que estás buscando es
comm
. p.ej:-Aquí:
-1 : suprime la columna 1 (líneas exclusivas de 1.sorted.txt)
-2 : suprime la columna 2 (líneas exclusivas de 2.sorted.txt)
fuente
grep
hace algunas cosas raras que no puede esperar. Específicamente, todo en1.txt
se interpretará como una expresión regular y no como una cadena simple. Además, cualquier línea en blanco1.txt
coincidirá con todas las líneas2.txt
. Porgrep
lo tanto , solo funcionará en situaciones muy específicas. Al menos te gustaría usarfgrep
(ogrep -f
) pero lo de la línea en blanco probablemente causará estragos en este proceso.grep -F -x -f file1 file2
comm
comando en 3 archivos separados? La respuesta fue demasiado grande para caber cómodamente aquí.Para aplicar fácilmente el comando comm a archivos sin clasificar , use la sustitución de procesos de Bash :
Por lo tanto, los archivos abc y def tienen una línea en común, la que tiene "132". Usando comm en archivos sin clasificar:
La última línea no produjo salida, la línea común no fue descubierta.
Ahora usa comm en archivos ordenados, ordenando los archivos con sustitución de proceso:
¡Ahora tenemos la línea 132!
fuente
sort abc > abc.sorted
,sort dev > def.sorted
y luegocomm -12 abc.sorted def.sorted
?Para complementar el Perl one-liner, aquí está su
awk
equivalente:Esto leerá todas las líneas de
file1
la matrizarr[]
y luego comprobará si cada líneafile2
ya existe dentro de la matriz (es decirfile1
). Las líneas que se encuentran se imprimirán en el orden en que aparecenfile2
. Tenga en cuenta que la comparaciónin arr
utiliza la línea completa desde elfile2
índice hasta la matriz, por lo que solo informará coincidencias exactas en líneas completas.fuente
perl
los, porque). Un millón de gracias, SraTal vez te refieres
comm
?El secreto para encontrar esta información son las páginas de información. Para los programas GNU, son mucho más detallados que sus páginas de manual. Pruebe
info coreutils
y le mostrará todas las pequeñas utilidades útiles.fuente
Mientras
le ofrece las diferencias de dos archivos (lo que está en 2.txt y no en 1.txt), podría hacer fácilmente un
para recopilar todas las líneas comunes, lo que debería proporcionar una solución fácil a su problema. Si ha ordenado archivos, no
comm
obstante , debe tomarlos . ¡Saludos!fuente
grep
hace algunas cosas raras que no podrías esperar. Específicamente, todo en1.txt
se interpretará como una expresión regular y no como una cadena simple. Además, cualquier línea en blanco1.txt
coincidirá con todas las líneas2.txt
. Entonces esto solo funcionará en situaciones muy específicas.grep
anotaciones POSIX , que son compatibles con lasgrep
variantes más modernas de Unix. Agregue-F
(o usefgrep
) para suprimir expresiones regulares. Agregue-x
(para exacto) para que coincida solo con líneas completas.comm
para archivos ordenados?comm
puede trabajar con archivos arbitrariamente grandes siempre que estén ordenados porque solo necesita mantener tres líneas en la memoria (supongo que GNUcomm
incluso sabría mantener solo un prefijo si las líneas son realmente largas). Lagrep
solución necesita mantener todas las expresiones de búsqueda en la memoria.Si los dos archivos aún no están ordenados, puede usar:
y funcionará, evitando el mensaje de error
comm: file 2 is not in sorted order
al hacerlocomm -12 a.txt b.txt
.fuente
<(command)
no es portátil para el shell POSIX, aunque funciona en Bash y algunos otros.fuente
comm
comando, ya que busca en cada línea defile1
infile2
dondecomm
solo se comparará si linen
infile1
es igual a linen
infile2
.comm
no compara simplemente la línea N en el archivo 1 con la línea N en el archivo 2. Puede gestionar perfectamente una serie de líneas insertadas en cualquier archivo (lo que es equivalente a eliminar una serie de líneas del otro archivo, por supuesto). Simplemente requiere que las entradas estén ordenadas.comm
respuestas si uno quiere mantener el orden. Mejor queawk
responder si uno no quiere duplicados.fuente
En una versión limitada de Linux (como un QNAP (nas) en el que estaba trabajando):
grep -f file1 file2
puede causar algunos problemas como dijo @ChristopherSchultz y el usogrep -F -f file1 file2
fue realmente lento (más de 5 minutos, no lo terminé, más de 2-3 segundos con el siguiente método en archivos de más de 20 MB)Entonces, esto es lo que hice:
Si
files.same.sorted
debe haber estado en el mismo orden que los originales, agregue esta línea para el mismo orden que el archivo1:o, para el mismo orden que el archivo2:
fuente
Solo como referencia si alguien todavía está buscando cómo hacer esto para varios archivos, vea la respuesta vinculada a Buscar líneas coincidentes en muchos archivos.
Combinando estas dos respuestas ( ans1 y ans2 ), creo que puede obtener el resultado que necesita sin ordenar los archivos:
Simplemente guárdelo, dele derechos de ejecución (
chmod +x compareFiles.sh
) y ejecútelo. Tomará todos los archivos presentes en el directorio de trabajo actual y hará una comparación de todos contra todos dejando en el archivo "matching_lines" el resultado.Cosas a mejorar:
fuente
Esto debería hacerlo.
fuente
rm -f file3.txt
si vas a eliminar el archivo; eso no informará ningún error si el archivo no existe. OTOH, no sería necesario si su secuencia de comandos simplemente se hizo eco de la salida estándar, permitiendo que el usuario de la secuencia de comandos elija a dónde debe ir la salida. En última instancia, es probable que desee utilizar$1
y$2
(argumentos de línea de comando) en lugar de nombres de archivo fijos (file1.out
yfile2.out
). Eso deja el algoritmo: va a ser lento. Se leeráfile2.out
una vez para cada líneafile1.out
. Será lento si los archivos son grandes (digamos varios kilobytes).grep -F
que lee un archivo en la memoria y luego hace un solo paso sobre el otro evita que se repita repetidamente sobre ambos archivos de entrada.