我有一个巨大的文件需要解析,需要搜索和替换文本,但在特定字段中,共享一个名为 dest 的小样本以供参考。第一行是供参考的标题。
cat dest
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||
1004|||50000
1005|||50001
我有单独的文件,其中包含要匹配的模式、要替换的文本和要替换的文本
cat src
1003||15003
1004|50000|15004
1005|50001|15005
所以我可以使用 sed 运行下面给定的 while 循环来实现 src 文件中的最后 2 行。
cat src | while IFS=$'|'; read id old new; do sed -i "/^${id}/s/${old}/${new}/" dest; done
但对于ID=1003
我得到的空字符串$old
,它将替换 dest 文件中该 ID 的所有空列。我想避免这种情况。我想做的是只替换最后一个字段。
期望:
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||15003
1004|||15004
1005|||15005
我可以使用 awk,因为它对于柱状数据来说更细粒度。但据我所知,awk 会多次打印到标准输出,这对我来说也不实用。
那么有没有一种方法可以让我以智能和简洁的方式做到这一点?
答案1
awk 'BEGIN{ FS=OFS="|" }
NR==FNR { id[$1, $2]=$3; next }
{ $4=( ($1, $4) in id? id[$1, $4]: $4) } 1' src dest
FS:F产量S迭代器
OFS:氧输出F产量S迭代器
NR==FNR:第一个输入文件的始终为真条件习惯用法。
NR 存在总数氮数量右awk 读取的记录;
FNR 存在于每个人中F伊莱的氮数量右记录。id[$1, $2]=$3
:关联的 awk 数组。名称:id
键:column#1+column#2
值:column#3第一个块仅针对第一个输入文件运行,i。 e、文件源代码。
在此$4=($1, $4) in id? id[$1, $4]: $4
,我们更新第二个文件 i 的最后一列($NF
或$4
)的值。 e、文件目的地来自column#1+column#4的匹配键组合ID数组,如果找到则返回该值 ( id[$1, $4]
),否则复制其当前值。
答案2
另一种awk
解决方案,假设来自的行src
将按顺序仅使用一次。这允许我们只跟踪下一行,直到src
它被使用为止,然后读取下一行。
awk -F '|' '
BEGIN { OFS=FS }
! have {
getline line <"src"
split(line, pat)
have = 1
}
$1 == pat[1] {
if ($4 == pat[2]) $4 = pat[3]
have = 0
}; 1' dest
如果该标志have
未设置或为零,则将src
读取下一行line
并将其拆分到数组中pat
。这是在! have
块中完成的。
如果当前输入行的dest
第一个字段与 的第一个元素相同pat
,那么我们将测试第四个字段,如果它们相同,pat[2]
则将其替换为。然后pat[3]
该have
标志重置为零以触发从 from 读取新行src
。
1
程序末尾的尾随awk
导致输出(可能已修改的)记录。
给出问题中的数据的输出:
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||15003
1004|||15004
1005|||15005