Usando awk
:
awk -v a='2,4,5,7' -v b='1,2,5,8' '
BEGIN { split(a, ax, ","); split(b, bx, ",");
for(n in ax) mapping[ bx[n] ] =ax[n];
};
NR==FNR { if (FNR in mapping) hold[ mapping[FNR] ]=$0; next; };
{ print (FNR in hold)? hold[FNR]: $0; }' fileB fileA
Aquí, pasamos números de línea como un awk -v
variable en a='...'
(para el archivo A) y b='...'
(para el archivo B), entonces split()
en una matriz con carácter de coma como separador (tenga en cuenta que a
y b
eran variables, mientras que ahora ax
y bx
son matrices).
luego construimos otro mapping
matriz de ax
y bx
arreglos para mapear las líneas que deben ser reemplazadas en el archivo A con las del archivo B;
ahora claves (o índices) del mapping
matriz son los números de línea del archivo B y los valores de estas claves son los números de línea del archivo A, como se muestra a continuación:
el mapping
matriz es:
Key Value
1 2
2 4
5 5
8 7
ahora lo que necesitamos, es decir, solo leer los números de línea del archivo B que coinciden con las claves anteriores (FNR de 1
, 2
, 5
y 8
), así que hacemos eso con:
NR==FNR { if (FNR in mapping) hold[ mapping[FNR] ]=$0; next; };
Bien, ahora cuál es el valor del mapping[FNR]
? si marcas el mapping
matriz anterior, sería:
mapping[1] --> 2; then-we-have hold[ mapping[1] ] --> hold[2]=$0
mapping[2] --> 4; then-we-have hold[ mapping[2] ] --> hold[4]=$0
mapping[5] --> 5; then-we-have hold[ mapping[5] ] --> hold[5]=$0
mapping[8] --> 7; then-we-have hold[ mapping[8] ] --> hold[7]=$0
así que usamos el valor de mapping
matriz como clave para el hold
matriz y hold
la matriz ahora contiene:
Key Value
2 Argentina
4 Switzerland
5 Denmark
7 Colombia
ahora el último paso es usar claves en hold
matriz como el número de línea coincidente en el archivo A y reemplace esas líneas con los valores de esa clave del hold
matriz si ese número de línea se encuentra en la matriz o imprime la línea en sí misma si no se encuentra (operador ternario:condition? if-true : if-false
), y lo hacemos con:
{ print (FNR in hold)? hold[FNR]: $0; }
Usando sed
estándar :
$ printf '%ds/^/%dc\\\\\\\n/p\n' 1 2 2 4 5 5 8 7 | sed -n -f /dev/stdin fileB | sed -f /dev/stdin fileA
Italy
Argentina
USA
Switzerland
Denmark
Japan
Colombia
La canalización de comandos,
printf '%ds/^/%dc\\\\\\\n/p\n' 1 2 2 4 5 5 8 7 |
sed -n -f /dev/stdin fileB |
sed -f /dev/stdin fileA
primero genera un sed
declaración sustituta para cada par de números de línea usando printf
. La salida del printf
la llamada es la siguiente sed
guión:
1s/^/2c\\\
/p
2s/^/4c\\\
/p
5s/^/5c\\\
/p
8s/^/7c\\\
/p
Este sed
el script actúa en las líneas 1, 2, 5 y 8 e inserta nc\
seguido de una nueva línea literal (para algún número de línea n
) al comienzo de las líneas afectadas.
Ejecutando esto a través de fileB
(con sed -n
) genera un nuevo sed
guión:
2c\
Argentina
4c\
Switzerland
5c\
Denmark
7c\
Colombia
El c
El comando reemplaza una línea con el texto que sigue al \
, por lo que la secuencia de comandos reemplazará las líneas 2, 4, 5 y 7.
Aplicando esto a fileA
genera el resultado.
Leer los números de línea de un archivo en el que la primera columna contiene números de línea para fileB
y la segunda columna contiene números de línea para fileA
:
$ cat number-pairs
1 2
2 4
5 5
8 7
$ awk '{ printf "%ds/^/%dc\\\\\\\n/p\n", $1, $2 }' number-pairs | sed -n -f /dev/stdin fileB | sed -f /dev/stdin fileA
Italy
Argentina
USA
Switzerland
Denmark
Japan
Colombia
Obviamente puedes intercambiar $1
y $2
en él awk
expresión si desea almacenar las columnas en el orden opuesto.