Utilizzando 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
Qui passiamo i numeri di riga come awk -v
ariabile in a='...'
(per fileA) e b='...'
(per fileB), quindi split()
in un array sul carattere virgola come separatore (nota che a
e b
erano variabili, mentre ora ax
e bx
sono array).
poi costruiamo un altro mapping
matrice da ax
e bx
array per mappare le linee che devono essere sostituite nel fileA con quelle del fileB;
ora chiavi (o indici) del mapping
array sono i numeri di riga del fileB e i valori di queste chiavi sono i numeri di riga del fileA, come di seguito:
il mapping
matrice è:
Key Value
1 2
2 4
5 5
8 7
quindi ora ciò di cui abbiamo bisogno, cioè solo leggere i numeri di riga dal fileB che corrispondono alle chiavi sopra (FNR di 1
, 2
, 5
e 8
), quindi lo facciamo con:
NR==FNR { if (FNR in mapping) hold[ mapping[FNR] ]=$0; next; };
OK, ora qual è il valore di mapping[FNR]
? se selezioni mapping
array sopra, sarebbe:
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
quindi abbiamo utilizzato il valore di mapping
array come chiave per hold
matrice e hold
l'array ora contiene:
Key Value
2 Argentina
4 Switzerland
5 Denmark
7 Colombia
ora l'ultimo passo è usare le chiavi in hold
array come numero di riga corrispondente nel fileA e sostituisci quelle righe con i valori di quella chiave dal hold
array se quel numero di riga è stato trovato nell'array o stampa la riga stessa se non è stata trovata (operatore ternario:condition? if-true : if-false
), e lo facciamo con:
{ print (FNR in hold)? hold[FNR]: $0; }
Utilizzando lo standard sed
:
$ 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 pipeline dei comandi,
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
prima genera un sed
sostituire l'istruzione per ogni coppia di numeri di riga utilizzando printf
. L'output di printf
call è il seguente sed
script:
1s/^/2c\\\
/p
2s/^/4c\\\
/p
5s/^/5c\\\
/p
8s/^/7c\\\
/p
Questo sed
lo script agisce sulla riga 1, 2, 5 e 8 e inserisce nc\
seguito da una nuova riga letterale (per alcuni numeri di riga n
) all'inizio delle righe interessate.
Eseguendolo su fileB
(con sed -n
) genera un nuovo sed
script:
2c\
Argentina
4c\
Switzerland
5c\
Denmark
7c\
Colombia
Il c
Il comando sostituisce una riga con il testo che segue il \
, quindi lo script sostituirà le righe 2, 4, 5 e 7.
Applicando questo a fileA
genera il risultato.
Lettura dei numeri di riga da un file in cui la prima colonna contiene i numeri di riga per fileB
e la seconda colonna contiene i numeri di riga per 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
Puoi ovviamente scambiare $1
e $2
in lui awk
expression se desideri memorizzare le colonne nell'ordine opposto.