用循环中的变量替换特定字段中的文本

用循环中的变量替换特定字段中的文本

我有一个巨大的文件需要解析,需要搜索和替换文本,但在特定字段中,共享一个名为 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

相关内容