GNU/Linux >> Tutoriales Linux >  >> Linux

Uniendo múltiples campos en archivos de texto en Unix

Probablemente sea más fácil combinar los tres primeros campos con awk:

awk '{print $1 "_" $2 "_" $3 " " $4}' filename

Entonces puedes usar join normalmente en el "campo 1"


Puedes probar esto

awk '{
 o1=$1;o2=$2;o3=$3
 $1=$2=$3="";gsub(" +","")
 _[o1 FS o2 FS o3]=_[o1 FS o2 FS o3] FS $0
}
END{ for(i in _) print i,_[i] }' file1 file2

salida

$ ./shell.sh
foo 1 scaf  3 4.5
bar 2 scaf  3.3 1.00
foo 1 boo  2.3

Si desea omitir líneas poco comunes

awk 'FNR==NR{
 s=""
 for(i=4;i<=NF;i++){ s=s FS $i }
 _[$1$2$3] = s
 next
}
{
  printf $1 FS $2 FS $3 FS
  for(o=4;o<NF;o++){
   printf $i" "
  }
  printf $NF FS _[$1$2$3]"\n"
 } ' file2 file1

salida

$ ./shell.sh
foo 1 scaf 3  4.5
bar 2 scaf 3.3  1.00

Aquí está el correcto respuesta (en términos de uso de GNU coreutils estándar herramientas y no escribir secuencias de comandos personalizadas en perl/awk lo que quieras).

$ join -j1 -o1.2,1.3,1.4,1.5,2.5 <(<file1 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1) <(<file2 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1)
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5

Bien, ¿cómo funciona?:

  1. En primer lugar utilizaremos una gran herramienta join que puede fusionar dos líneas. join tiene dos requisitos:

    • Podemos unirnos solo por un solo campo.
    • Ambos archivos deben estar ordenados por columna clave!
  2. Necesitamos generar claves en archivos de entrada y para eso usamos un simple awk guión:

    $ cat file1
    foo 1 scaf 3
    bar 2 scaf 3.3    
    
    $ <file1 awk '{print $1"-"$2"-"$3" "$0}'
    foo-1-scaf foo 1 scaf 3
    bar-2-scaf bar 2 scaf 3.3
    

    Verá, agregamos la primera columna con alguna clave como "foo-1-scaf ".Hacemos lo mismo con archivo2 .POR CIERTO. <file awk , es una forma elegante de escribir awk file , o cat file | awk .

    También debemos ordenar nuestros archivos por la clave, en nuestro caso esta es la columna 1, por lo que agregamos al final del comando el | sort -k1,1 (ordenar por texto de la columna 1 a la columna 1)

  3. En este punto, solo podríamos generar archivos file1.with.key y archivo2.con.clave y únase a ellos, pero supongamos que esos archivos son enormes, no queremos copiarlos en el sistema de archivos. En su lugar, podemos usar algo llamado bash Procesar la sustitución para generar la salida en la canalización con nombre (esto evitará la creación de archivos intermedios innecesarios). Para obtener más información, lea el enlace provisto.

    Nuestra sintaxis objetivo es:join <( some command ) <(some other command)

  4. Lo último es explicar los argumentos de combinación sofisticados:-j1 -o1.2,1.3,1.4,1.5,2.5

    • -j1 - unirse por clave en la primera columna (en ambos archivos)
    • -o - mostrar solo esos campos 1.2 (1er archivo campo2), 1.3 (1er archivo columna 3), etc.

      De esta manera unimos líneas, pero join genera solo las columnas necesarias.

Las lecciones aprendidas de esta publicación deberían ser:

  • debes dominar las coreutils paquete, esas herramientas son muy poderosas cuando se combinan y casi nunca es necesario escribir un programa personalizado para tratar estos casos,
  • Las herramientas básicas de utilidades también son ultrarrápidas y están muy probadas, por lo que siempre son la mejor opción.

El comando unir es difícil de usar y solo se une en una columna

La experimentación extensiva más el escrutinio minucioso de las páginas del manual indican que no puede unir directamente varias columnas, y todos mis ejemplos prácticos de unión, curiosamente, usan solo una columna de unión.

En consecuencia, cualquier solución requerirá que las columnas que se unirán se concatenen en una sola columna, de alguna manera. El comando de unión estándar también requiere que sus entradas estén en el orden correcto:hay un comentario en la unión de GNU (unión de información coreutils) acerca de que no siempre requiere datos ordenados:

Sin embargo, como una extensión de GNU, si la entrada no tiene líneas que no se puedan emparejar, el orden de clasificación puede ser cualquier orden que considere que dos campos son iguales si y solo si la comparación de clasificación descrita anteriormente los considera iguales.

Una forma posible de hacerlo con los archivos dados es:

awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file1 |
sort > sort1
awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file2 |
sort > sort2
join -1 1 -2 1 -o 1.2,1.3,1.4,1.5,2.5 sort1 sort2

Esto crea un campo de ordenación compuesto al principio, usando ':' para separar los subcampos, y luego ordena el archivo, para cada uno de los dos archivos. Luego, el comando de unión une los dos campos compuestos, pero imprime solo los campos no compuestos (no unidos).

La salida es:

bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5

Intentos fallidos de hacer que la unión haga lo que no hará

unirse -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 archivo1 archivo2

En MacOS X 10.6.3, esto da:

$ cat file1
foo 1 scaf 3 
bar 2 scaf 3.3
$ cat file2
foo 1 scaf 4.5
foo 1 boo 2.3
bar 2 scaf 1.00
$ join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
foo 1 scaf 3 4.5 
bar 2 scaf 3.3 4.5 
$

Esto se une en el campo 3 (solo), que no es lo que se desea.

Debe asegurarse de que los archivos de entrada estén en el orden correcto.


Linux
  1. Importar múltiples archivos SQL en MySQL

  2. Cómo unir dos archivos de texto en Linux

  3. Cómo comprimir varios archivos en Linux

  4. ¿Cómo cambiar el nombre de varios archivos en un solo comando o secuencia de comandos en Unix?

  5. Linux – Unir dos archivos ordenados da error:Unirse::112855:¿No está ordenado:?

Comando Grep en Linux (Buscar texto en archivos)

Comando Renombrar en Linux (Renombrar Múltiples Archivos)

Cómo unir/combinar varios archivos de audio en uno solo en Linux

Encuentra texto en archivos en Linux usando grep

Dd:¿Múltiples archivos de entrada?

Comando ls en Linux/UNIX