あるファイルの行を行番号で別のファイルの行に置き換えます。

あるファイルの行を行番号で別のファイルの行に置き換えます。

多くの行を含むfileA.txtがあり、特定の行を複数行を含む2番目のファイルfileB.txtの他の特定の行に置き換えたいと思います。

例: ファイル A.txt

Italy
Korea
USA
England
Peru
Japan
Uruguay

ファイルB.txt

Argentina
Switzerland
Spain
Greece
Denmark
Singapore
Thailand
Colombia

最初のファイルの2、4、5、7行を2番目のファイルの1、2、5、8行に置き換えたいと思います。

出力:

Italy
Argentina
USA
Switzerland
Denmark
Japan
Colombia

awkやsedでできるようですが、awkの場合、このコードは2番目のファイルに関する行情報を提供していないようです。

awk 'NR==FNR{ a[$2]=$1; next }FNR in a{ $0=a[FNR] }1' fileA.txt fileB.txt

どんな提案がありますか?

答え1

使用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

ここでは、行番号を次のように使用します。アッ -va='...'変数が(ファイルAの場合)およびb='...'(ファイルBの場合)にある場合split()これをコンマ文字で区切られた配列に入れます(aおよびはb変数、現在axbx配列です)。

mapping次に、ax配列から別の配列を作成し、bxfileAの行をfileBの行に置き換える必要があります。

現在のキー(またはインデックス)mappingarrayはfileBの行番号であり、これらのキーの値は次のようにfileAの行番号です。

配列mappingは次のとおりです

Key    Value
1      2
2      4
5      5
8      7

1今私たちに必要なのは、上記のキー(、、、2および5FNR)と一致するfileBの行番号を読むことです。8したがって、次のようにします。

NR==FNR { if (FNR in mapping) hold[ mapping[FNR] ]=$0; next; };

さて、今価値はいくらですかmapping[FNR]mapping上記の配列を確認すると、次のようになります。

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

したがって、配列の値をmapping配列のキーとして使用します。これには以下が含まれます。holdhold

Key     Value
2       Argentina
4       Switzerland
5       Denmark
7       Colombia

最後のステップは、配列のキーをfileAの一致する行番号として使用することですhold。その行番号が配列にある場合は、その行を配列の対応するキー値に置き換え、見つからholdない場合は行を印刷します。独自に (3 つのメタ演算子: condition? if-true : if-false) 次のようにします。

{ print (FNR in hold)? hold[FNR]: $0; }

答え2

使用標準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

コマンドパイプライン、

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

まず、sed各行番号のペアに対して代替文を生成しますprintf。呼び出しの出力はprintf次のsedスクリプトです。

1s/^/2c\\\
/p
2s/^/4c\\\
/p
5s/^/5c\\\
/p
8s/^/7c\\\
/p

このスクリプトは行1、2、5、8で動作し、sed影響を受けた行の先頭にnc\リテラル改行文字(特定の行番号の場合)を挿入します。n

このコマンドを実行するとfileB(を使用してsed -n)新しいsedスクリプトが生成されます。

2c\
Argentina
4c\
Switzerland
5c\
Denmark
7c\
Colombia

このcコマンドは1行を次のテキストに置き換えるため、\スクリプトは2行、4行、5行、7行を置き換えます。

これを適用してfileA結果を生成します。

fileB最初の列に行番号が含まれ、2番目の列に行番号が含まれているファイルから行番号が読み取られます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

列を逆順に保存するには、式でおよびを明確に置き換えることができます$1$2awk

関連情報