Pao*_*ini 5 linux sed awk text-processing
我有一个多行的 fileA.txt,我想用第二个文件 fileB.txt 中的其他特定行替换特定行,该文件也有很多行
例如:fileA.txt
Italy
Korea
USA
England
Peru
Japan
Uruguay
Run Code Online (Sandbox Code Playgroud)
文件B.txt
Argentina
Switzerland
Spain
Greece
Denmark
Singapore
Thailand
Colombia
Run Code Online (Sandbox Code Playgroud)
我想用第二个文件中的第 1、2、5 和 8 行替换第一个文件中的第 2、4、5 和 7 行:
输出:
Italy
Argentina
USA
Switzerland
Denmark
Japan
Colombia
Run Code Online (Sandbox Code Playgroud)
我想我可以用 awk 或 sed 来完成,但如果 awk 这段代码似乎没有提供第二个文件的行信息:
awk 'NR==FNR{ a[$2]=$1; next }FNR in a{ $0=a[FNR] }1' fileA.txt fileB.txt
Run Code Online (Sandbox Code Playgroud)
有什么建议吗?
使用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
Run Code Online (Sandbox Code Playgroud)
在这里,我们通过行号为AWK -v
在良莠不齐a='...'
(为的fileA)和b='...'
(对于FILEB),那么我们split()
他们到一个数组的逗号作为分隔符(注意,a
并b
为变量,而现在ax
和bx
是数组)。
然后我们构建另一个mapping
数组 fromax
和bx
arrays 来映射那些应该在 fileA 中替换的行与来自 fileB 的行;
现在mapping
数组的键(或索引)是文件B的行号,这些键的值是文件A的行号,如下所示:
该mapping
阵列是:
Key Value
1 2
2 4
5 5
8 7
Run Code Online (Sandbox Code Playgroud)
所以现在我们需要做的,就是从 fileB 中读取与上面的键匹配的行号(FNRs of 1
, 2
, 5
and 8
),所以我们这样做:
NR==FNR { if (FNR in mapping) hold[ mapping[FNR] ]=$0; next; };
Run Code Online (Sandbox Code Playgroud)
好的,现在 的值是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
Run Code Online (Sandbox Code Playgroud)
所以我们使用mapping
数组的值作为数组的键hold
,hold
数组现在包含:
Key Value
2 Argentina
4 Switzerland
5 Denmark
7 Colombia
Run Code Online (Sandbox Code Playgroud)
现在最后一步是使用hold
数组中的键作为 fileA 中匹配的行号,hold
如果在数组中找到该行号,则用数组中该键的值替换该行,如果未找到则打印该行本身(三元运算符:condition? if-true : if-false
),我们这样做:
{ print (FNR in hold)? hold[FNR]: $0; }
Run Code Online (Sandbox Code Playgroud)
使用标准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
Run Code Online (Sandbox Code Playgroud)
命令管道,
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
Run Code Online (Sandbox Code Playgroud)
首先sed
使用 为每对行号生成一个替换语句printf
。printf
调用的输出是以下sed
脚本:
1s/^/2c\\\
/p
2s/^/4c\\\
/p
5s/^/5c\\\
/p
8s/^/7c\\\
/p
Run Code Online (Sandbox Code Playgroud)
此sed
脚本作用于第 1、2、5 和 8 行,并在受影响的行的开头插入nc\
后跟文字换行符(对于某些行号n
)。
在fileB
(with sed -n
) 上运行它会生成一个新sed
脚本:
2c\
Argentina
4c\
Switzerland
5c\
Denmark
7c\
Colombia
Run Code Online (Sandbox Code Playgroud)
该c
命令用 后面的文本替换一行\
,因此脚本将替换第 2、4、5 和 7 行。
应用它来fileA
生成结果。
从文件中读取行号,其中第一列包含 的行号fileB
,第二列包含 的行号fileA
:
1s/^/2c\\\
/p
2s/^/4c\\\
/p
5s/^/5c\\\
/p
8s/^/7c\\\
/p
Run Code Online (Sandbox Code Playgroud)
2c\
Argentina
4c\
Switzerland
5c\
Denmark
7c\
Colombia
Run Code Online (Sandbox Code Playgroud)
如果你想以相反的顺序存储列,你显然可以在他的表达式中交换$1
和。$2
awk