比较 File1 和 File2 以注释掉 File2 中的匹配模式

比较 File1 和 File2 以注释掉 File2 中的匹配模式

我有 2 个文件,它们是包含测试名称的列表。一个文件包含基本测试名称,例如usb30_tb_7_10,在另一个文件中显示为'include "usb30_tb_7_10.sv".我想获取所有名字列表`这是基本名称(不包括或 .sv)并在中找到它们列表2并注释掉整行。

IE:

清单1

test1
test3

评论前列表2

'include "test1.sv"
'include "test2.sv"
'include "test3.sv"
'include "test4.sv"

列表2 比较后

//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
'include "test4.sv"

我对 grep/sed/awk 还是新手,但我还没有找到解决方案。

我见过涉及 awk 的答案,它采用特定模式作为输入,但这对我没有太大帮助。

我尝试执行以下操作:

awk '-include list1.lst {print "// " $0; next} 1' list2.sv

但它不起作用(甚至因为输入错误而接受命令)。

答案1

使用 awk:

$ awk -F'[".]' 'NR==FNR{a[$0]; next} $2 in a{$0="//"$0} 1' list1 list2
//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
'include "test4.sv"

怎么运行的:

  • -F'[".]'

    "这告诉 awk 在出现or时分隔字段.

  • NR==FNR{a[$0]; next}

    当读取第一个文件 时list,这告诉 awk 在关联数组中创建一个a等于当前行的键,然后跳过其余命令并跳转到该next行。

    更详细:NR是 awk 到目前为止已读取的总行数。 FNR是迄今为止从当前文件读取的行数。此时FNR==NR,我们正在读取第一个文件。

  • $2 in a{$0="//"$0}

    当读取第二个文件时,如果当前行中的第二个字段是关联数组中的键,这会告诉 awk 添加//到行的开头a

  • 1

    这是 awk 对 print-the-line 的神秘简写。

扩展示例

使用评论中提到的附加行:

$ cat list1
test1
test3
usb30_suspend_resume
$ cat list2
'include "test1.sv"
'include "test2.sv"
'include "test3.sv"
'include "usb30_suspend_resume.sv"
'include "test4.sv"
$ awk -F'[".]' 'NR==FNR{a[$0]; next} $2 in a{$0="//"$0} 1' list1 list2
//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
//'include "usb30_suspend_resume.sv"
'include "test4.sv"

适应pastebin文件

Pastebin 上的文件在 list1 中具有尾随空白,并且两个文件都具有 Windows 样式的行结尾。要处理此格式,请使用:

awk 'NR==FNR{a[$1]; next} $2 in a{$0="//"$0} 1' FS='[[:space:]]' list1.txt FS='[".]' list2.txt

答案2

坦率地说,我会在 Vim 中以交互方式完成此操作,所用的时间比键入迄今为止给出的任何脚本解决方案所需的时间都要短。

vim list2

然后,读取顶部的 list1。 (我假设很容易从视觉上看出 list2 的结束位置和 list2 的开始位置,因此无需提前标记任何内容,但:1k a如果您愿意,可以先标记 list2 的原始第 1 行。)

:0r list1

执行此命令后,您的光标将位于文件开头的第一个单词上test1

按此键*转到光标下单词的下一个实例。 (这将是您要评论的行。)

I进入插入模式(在该行的第一个非空白字符处,因为您使用的是大写I而不是小写)并键入//,然后按 Escape。

按此键n转到搜索词的下一个实例。 (由于您位于字符后面的行开头//,因此您的光标将转到您刚刚找到的实例。因此,再次按它即可转到下一个实例。)

假设只有一个实例需要注释,您现在将再次位于文件的开头 — 第一行。按j向下移动(或者只需按 Enter 转到下一行的第一个非空白字符 — 在本例中结果相同)。

*转到下一个test3实例,因为这就是您现在光标所在的实例。

.重复“注释掉行”操作。 点命令很棒。 :)

再按n一次。 (两次。)在您的示例文本中,您现在已经完成了 - 您回到了第二行,test3。如果还有更多行需要注释,再次只需键入j*.nn。如果还有另一个,请j*.nn再次输入。

完成后(您位于test3或来自 的最后一行list1,就在来自 的原始第一行上方list2),按dgg删除从当前行到文件第一行的所有行,这样list1条目就不会出现在那里不再了。

总共,您输入的是

vim list2<Enter>

打开文件,然后:

:0r list1<Enter>
*I//<Esc>nn
j*.nn
j*.nn
j*.nn
(Repeat however many times)
dgg

然后要保存并退出,请键入:x并按 Enter。


编辑:

我了解到你的“list1”很大。没关系;只需使用宏即可。

执行上述操作几次后确定其有效,然后输入:

qkj*.nnq

这将j*.nn在寄存器中记录为宏k

通过键入 运行宏@k

输入 再次运行它@@

然后输入 运行它 4000 次4000@@。但就我个人而言,我会分成更小的部分来完成。也许不在宏中使用点命令,而是显式键入I//<Esc>

重点是,我会仍然交互地做,它会仍然不管我要处理多少行,只需要一两分钟。 Vim 的魔力。 :)

答案3

算法是:

 for each line of List2
     if line matches ANY pattern in List1 then
         print //line
     else
         print line

这是 bash (或类似)中的实现:

 while read line ;do
     if echo $line | fgrep -f List1 >/dev/null ;then
         echo "//$line"
     else
         echo "$line"
     fi
 done < List2

相关内容