按行号将一个文件中的行替换为另一个文件中的行

按行号将一个文件中的行替换为另一个文件中的行

我有一个包含很多行的 fileA.txt,我想用第二个文件 fileB.txt 中的其他特定行替换特定行,该文件也包含很多行

例如:文件A.txt

Italy
Korea
USA
England
Peru
Japan
Uruguay

文件B.txt

Argentina
Switzerland
Spain
Greece
Denmark
Singapore
Thailand
Colombia

我想用第二个文件中的第 1、2、5 和 8 行替换第一个文件中的第 2、4、5 和 7 行:

输出:

Italy
Argentina
USA
Switzerland
Denmark
Japan
Colombia

我想我可以用 awk 或 sed 来完成,但是如果 awk 这段代码似乎没有提供第二个文件的行信息:

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

在这里,我们将行号作为awk -v变量在a='...'(对于文件A)和b='...'(对于文件B)中,那么我们split()将它们放入一个以逗号字符作为分隔符的数组中(请注意,ab是变量,而现在axbx是数组)。

mapping然后我们从ax和数组构建另一个数组bx,以映射 fileA 中应替换为 fileB 中的行;

现在的键(或索引)mappingarray 是 fileB 的行号,这些键的值是 fileA 的行号,如下:

mapping数组是:

Key    Value
1      2
2      4
5      5
8      7

所以现在我们需要的,就是从 fileB 中读取与上面的键匹配的行号(125的FNR 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

现在最后一步是使用hold数组中的键作为 fileA 中匹配的行号,如果在数组中找到该行号,则将这些行替换为数组中该键的值,hold如果未找到,则打印该行本身(三元运算符: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

sed脚本作用于第 1、2、5 和 8 行,并在受影响的行的开头插入nc\一个文字换行符(对于某些行号)。n

运行此命令fileB(使用sed -n)会生成一个新sed脚本:

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

c命令用 后面的文本替换一行\,因此脚本将替换第 2、4、5 和 7 行。

应用它来fileA生成结果。

从文件中读取行号,其中第一列包含 的行号fileB,第二列包含 的行号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

如果您想以相反的顺序存储列,显然可以在表达式中交换$1and 。$2awk

相关内容