为什么在使用 shell 脚本替换文件并在第二个文件中查找时,某些行会出现空白?

Why do I get blanks on some rows when using shell script to replace in file with lookup in second file?

我有一个文件data.txt,内容

2013-04-24;1;0.1635;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085546
2013-04-24;1;0.9135;1.4135;fp.3.Luci_01A01.ctg.ctg7180000038386
2017-04-24;2;0.9135;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085546
2011-04-24;2;0.9135;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085546
2012-04-24;2;0.9135;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085549
2016-04-24;2;0.9135;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085549
2016-04-24;2;0.9135;1.4335;fp.3.Luci_02C06.ctg.ctg7180000085549
2013-04-24;1;0.9135;1.4135;fp.3.Luci_01A01.ctg.ctg7180000038386
2011-04-24;2;0.9135;1.4135;fp.3.Luci_02C06.ctg.ctg7180000085546

和另一个文件 lookup.txt,内容为

1;2012-04-24;2ab1e4c0-de4d-11e2-a934-0f0479162b1b;fp.3.Luci_02C06.ctg.ctg7180000085546
7;2013-04-24;2ab21e90-de4d-11e2-9ce8-d368d9512bad;fp.3.Luci_01A01.ctg.ctg7180000038386
3;2014-04-24;2ab2582e-de4d-11e2-bb5f-6b1f6c4437f8;fp.3.Luci_02C06.ctg.ctg7180000085549

我想根据 lookup.txt 中第 4 列中的匹配值,将 data.txt 中的第 5 列替换为 lookup.txt 中的第 1 列。我要的结果是

2013-04-24;1;0.1635;1.4135;1
2013-04-24;1;0.9135;1.4135;7
2017-04-24;2;0.9135;1.4135;1
2011-04-24;2;0.9135;1.4135;1
2012-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4335;3
2013-04-24;1;0.9135;1.4135;7
2011-04-24;2;0.9135;1.4135;1

another post 我发现了以下 shell 看起来很有前途的脚本

awk -F';' 'NR==FNR{a[]=;next}{=a[]}1' lookup.txt data.txt

但由于某种原因,下面的结果在第 5、6、7 和 9 行的第 5 列留空。为什么?事实上,我们得到 space 分隔符而不是“;”也是一个问题,但没那么重要

2013-04-24 1 0.1635 1.4135 1
2013-04-24 1 0.9135 1.4135 7
2017-04-24 2 0.9135 1.4135 1
2011-04-24 2 0.9135 1.4135 1
2012-04-24 2 0.9135 1.4135
2016-04-24 2 0.9135 1.4135
2016-04-24 2 0.9135 1.4335
2013-04-24 1 0.9135 1.4135 7
2011-04-24 2 0.9135 1.4135

您可以使用这个 awk 解决方案:

awk '
BEGIN{FS=OFS=";"}
{
   sub(/\r$/, "")
} 
NR == FNR {
   map[$NF] = 
   next
}
{
   $NF = map[$NF]
} 1' lookup.txt data.txt

2013-04-24;1;0.1635;1.4135;1
2013-04-24;1;0.9135;1.4135;7
2017-04-24;2;0.9135;1.4135;1
2011-04-24;2;0.9135;1.4135;1
2012-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4335;3
2013-04-24;1;0.9135;1.4135;7
2011-04-24;2;0.9135;1.4135;1

解释:

  • BEGIN{FS=OFS=";"}:将输入和输出字段定界符设置为;
  • 在两个文件中始终使用 NF 而不是编号列
  • sub(/\r$/, "") 是删除行尾的所有回车符

通过在 FNR==NR 步骤取消 NF,它与显式使用 next 语句具有相同的效果。

如果您非常确定替换值永远不会为零,那么最终条件可以简化为 $NF = __[$NF]

mawk 'FNR==NR { NF=_*(__[$NF]=$!_) }_!~($NF=__[$NF])' RS='[\r]?[\n]' 
                                                   FS=';'
                                                  OFS=';' test_lookup_0005.txt 
                                                          test_data_0005.txt

2013-04-24;1;0.1635;1.4135;1
2013-04-24;1;0.9135;1.4135;7
2017-04-24;2;0.9135;1.4135;1
2011-04-24;2;0.9135;1.4135;1
2012-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4135;3
2016-04-24;2;0.9135;1.4335;3
2013-04-24;1;0.9135;1.4135;7
2011-04-24;2;0.9135;1.4135;1