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

commrequiere 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",commno hace el trabajo.pr-123-xy-45y el archivo2 contieneec11_orop_pr-123-xy-45.gz. Necesito el archivo 3 que contieneec11_orop_pr-123-xy-45.gzRespuestas:
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
grephace algunas cosas raras que no puede esperar. Específicamente, todo en1.txtse interpretará como una expresión regular y no como una cadena simple. Además, cualquier línea en blanco1.txtcoincidirá con todas las líneas2.txt. Porgreplo 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 file2commcomando 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.sortedy luegocomm -12 abc.sorted def.sorted?Para complementar el Perl one-liner, aquí está su
awkequivalente:Esto leerá todas las líneas de
file1la matrizarr[]y luego comprobará si cada líneafile2ya 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 arrutiliza la línea completa desde elfile2índice hasta la matriz, por lo que solo informará coincidencias exactas en líneas completas.fuente
perllos, 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 coreutilsy 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
commobstante , debe tomarlos . ¡Saludos!fuente
grephace algunas cosas raras que no podrías esperar. Específicamente, todo en1.txtse interpretará como una expresión regular y no como una cadena simple. Además, cualquier línea en blanco1.txtcoincidirá con todas las líneas2.txt. Entonces esto solo funcionará en situaciones muy específicas.grepanotaciones POSIX , que son compatibles con lasgrepvariantes 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.commpara archivos ordenados?commpuede trabajar con archivos arbitrariamente grandes siempre que estén ordenados porque solo necesita mantener tres líneas en la memoria (supongo que GNUcommincluso sabría mantener solo un prefijo si las líneas son realmente largas). Lagrepsolució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 orderal hacerlocomm -12 a.txt b.txt.fuente
<(command)no es portátil para el shell POSIX, aunque funciona en Bash y algunos otros.fuente
commcomando, ya que busca en cada línea defile1infile2dondecommsolo se comparará si lineninfile1es igual a lineninfile2.commno 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.commrespuestas si uno quiere mantener el orden. Mejor queawkresponder 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 file2puede causar algunos problemas como dijo @ChristopherSchultz y el usogrep -F -f file1 file2fue 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.sorteddebe 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.txtsi 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$1y$2(argumentos de línea de comando) en lugar de nombres de archivo fijos (file1.outyfile2.out). Eso deja el algoritmo: va a ser lento. Se leeráfile2.outuna vez para cada líneafile1.out. Será lento si los archivos son grandes (digamos varios kilobytes).grep -Fque 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.