我有一个包含很多行的 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()
将它们放入一个以逗号字符作为分隔符的数组中(请注意,a
和b
是变量,而现在ax
和bx
是数组)。
mapping
然后我们从ax
和数组构建另一个数组bx
,以映射 fileA 中应替换为 fileB 中的行;
现在的键(或索引)mapping
array 是 fileB 的行号,这些键的值是 fileA 的行号,如下:
该mapping
数组是:
Key Value
1 2
2 4
5 5
8 7
所以现在我们需要的,就是从 fileB 中读取与上面的键匹配的行号(1
、2
和5
的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
的键,数组现在包含:hold
hold
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
如果您想以相反的顺序存储列,显然可以在表达式中交换$1
and 。$2
awk