Quiero unirme a los 2 archivos de la segunda columna.

# cat vmid
10   win7-x64-17   [datastore1]   win7-kms-17/win7-template_1.vmx   windows7_64Guest   vmx-08
11   win7-x64-18   [datastore1]   win7-kms-18/win7-template_1.vmx   windows7_64Guest   vmx-08
4   win7-x64-11   [datastore1]   win7-kms-11/win7-template_1.vmx   windows7_64Guest   vmx-08
5   win7-x64-12   [datastore1]   win7-kms-12/win7-template_1.vmx   windows7_64Guest   vmx-08
6   win7-x64-13   [datastore1]   win7-kms-13/win7-template_1.vmx   windows7_64Guest   vmx-08
7   win7-x64-14   [datastore1]   win7-kms-14/win7-template_1.vmx   windows7_64Guest   vmx-08
8   win7-x64-15   [datastore1]   win7-kms-15/win7-template_1.vmx   windows7_64Guest   vmx-08
9   win7-x64-16   [datastore1]   win7-kms-16/win7-template_1.vmx   windows7_64Guest   vmx-08

# cat mac
00:0c:29:2f:00:d8   win7-kms-11
00:0c:29:db:f1:15   win7-kms-12
00:0c:29:ca:a3:d3   win7-kms-13
00:0c:29:f1:5e:ef   win7-kms-14
00:0c:29:1a:55:a6   win7-kms-15
00:0c:29:77:2e:93   win7-kms-16
00:0c:29:ae:5f:7f   win7-kms-17
00:0c:29:20:b4:aa   win7-kms-18

Salida esperada (sin clasificar, no se preocupe):

10  win7-x64-17     00:0c:29:ae:5f:7f
11  win7-x64-18     00:0c:29:20:b4:aa
4  win7-x64-11      00:0c:29:2f:00:d8
5  win7-x64-12      00:0c:29:db:f1:15
6  win7-x64-13      00:0c:29:ca:a3:d3
7  win7-x64-14      00:0c:29:f1:5e:ef
8  win7-x64-15      00:0c:29:1a:55:a6
9  win7-x64-16      00:0c:29:77:2e:93

Y a continuación están mis 2 intentos. Ambos no devuelven nada :

# awk 'NR==FNR {a[$2]=$1;next } ($2 in a) {print $2" "a[$2]" "$1 }' vmid mac
# join -j 2 <(sort -k 2 vmid) <(sort -k 2 mac)

Sé que mis comandos funcionan bien porque cuando lo intento en una entrada de prueba, ambos comandos anteriores funcionaron como se esperaba como se muestra a continuación:

# cat f1
82  d   
83  r
10  k
12  s

# cat f2
m   r
b   d
p   k
p   s

# join -j 2 <(sort -k 2 f1) <(sort -k 2 f2)
d 82  b
k 10 p
r 83 m
s 12 p

# awk 'NR==FNR {a[$2]=$1;next } ($2 in a) {print $2" "a[$2]" "$1 }' f1 f2 
r 83 m
d 82 b
k 10 p
s 12 p

Cualquier puntero sería realmente útil.

Gracias.

2
slayedbylucifer 25 ene. 2016 a las 17:08

3 respuestas

La mejor respuesta

Con join puedes usar el siguiente comando:

join -1 4 -2 2 <(tr '/' ' ' <vmid | sort -k4) <(sort -k2 mac) | cut -d' ' -f1,2,8

Explicación:

join -1 4 -2 2 une los archivos de entrada según la columna 4 del primer archivo de entrada y la columna 2 del segundo archivo de entrada.

Sin embargo, join espera que los archivos estén ordenados por esas columnas para que funcionen como se esperaba. También necesitamos separar win7-kms-1 de win7-kms-1/win7-template_1.vmx, lo que significa reemplazar / por un espacio para presentarlo como una columna separada de join. Puede preparar los archivos relacionados con esto antes de llamar a join, pero también puede usar sustitución de procesos (como mostré).

Al final, estoy usando cut para seleccionar solo las columnas de interés.


Hasta ahora, el comando join. Quería explicar eso. Una alternativa para resolver su caso de uso sería usar awk como ya mencionó. De hecho, yo sugeriría eso.

Casi estabas allí, pero debería estar:

awk -F'[[:space:]/]+' 'NR==FNR{s[$4]=$1;next}$2 in s{print s[$2],$2,$1}' vmid mac

Estoy usando uno o más espacios o / caracteres para delimitar campos. Esto facilita el acceso a win7-kms-1 en el campo $4.

NR == FNR es verdadero siempre que el número de línea total sea igual al número de línea en el archivo actual. En realidad, esto solo es cierto siempre que leamos el primer archivo de entrada. Usamos eso para crear una tabla de búsqueda de vmid y almacenar el campo uno basado en el campo cuatro.

$2 in s{print s[$2],$2,$1} comprueba entonces las líneas de mac si aparecen en la búsqueda e imprime los valores de interés en ese caso.

2
hek2mgl 25 ene. 2016 a las 20:12

¿Qué tal algo como esto (en perl):

#!/usr/bin/env perl

use strict;
use warnings; 

my %mac_lookup;

while ( <> ) {
   my @fields = split; 
   if ( $fields[0] =~ m/^\d{2}:/ ) { 
       $mac_lookup{$fields[1]} = $fields[0]
   }
   else {
       my ( $key ) = $fields[3] =~ m,([\w\-]+)/,;
       print join "\t", @fields[0,1], $mac_lookup{$key},"\n";
   }
}

Esto funcionará cuando se le proporcionen los nombres de archivo en la línea de comandos o mediante stdin.

  • iterar línea por línea
  • si comienza con \d{2}:, asuma que es un par mac- & gt; host, e insértelo en %mac_lookup
  • De lo contrario, suponga que es una línea de datos
  • extraer la clave del cuarto campo (las matrices comienzan en 0 en perl)
  • use esa clave para leer el hash.

Dando:

10  win7-x64-17 00:0c:29:ae:5f:7f   
11  win7-x64-18 00:0c:29:20:b4:aa   
4   win7-x64-11 00:0c:29:2f:00:d8   
5   win7-x64-12 00:0c:29:db:f1:15   
6   win7-x64-13 00:0c:29:ca:a3:d3   
7   win7-x64-14 00:0c:29:f1:5e:ef   
8   win7-x64-15 00:0c:29:1a:55:a6   
9   win7-x64-16 00:0c:29:77:2e:93

Nota: el orden coincidirá con el orden de los archivos, no el orden.

Esto colapsará en una sola línea si lo desea (aunque en mi opinión, eso generalmente no es algo bueno, los resultados son difíciles de leer).

perl -lane 'if($F[0] =~ m/^\d{2}:/){$M{$F[1]}=$F[0]}else{print join "\t", @F[0,1], $M{$F[3]=~s|/.*||r},"\n"}'
0
Sobrique 25 ene. 2016 a las 14:42

Usando awk (asumiendo que las palabras son siempre kms y x64):

awk 'NR==FNR{sub("kms","x64",$2);a[$2]=$1;next}{print $1 ,$2,a[$2];}' mac vmid
1
Guru 25 ene. 2016 a las 14:29