需要了解下面的 awk 命令来查找文件中丢失的行

需要了解下面的 awk 命令来查找文件中丢失的行

发现下面的awk命令可以找到与1.txt相比缺少的行2.txt

awk 'NR==FNR{b[$0]=1;next}!b[$0]' 1.txt 2.txt

需要逐步了解该awk构造如何找到缺失的行。

答案1

该脚本输出第二个文件中第一个文件中未出现的任何行。

awk 'NR==FNR { b[$0] = 1; next } !b[$0]' 1.txt 2.txt

awk脚本首先与 进行NR比较FNRNR是迄今为止读取的总共记录(行)数,包括当前记录。 FNR是从读取的记录数当前的输入文件。如果这两个数字相同,那么我们仍在阅读第一的输入文件。请注意,这会崩溃如果第一个文件恰好是空的NR == FNR对于第二个文件也是如此。

如果我们正在读取第一个输入文件(我们假设它非空),b[$0] = 1将使用当前记录的内容作为哈希键,并将该键的值 1 存储在数组中b(数组索引可能是awk) 中的字符串。然后执行脚本next,这意味着它跳回到脚本的开头并读取下一条记录。

如果NR不是等于FNR,那么这意味着我们正在读取第二是两个输入文件的一个测试,以当前输入记录(行)作为我们之前填充的!b[$0]数组的键。b如果 中的当前记录存储了 1 b,那么我们就知道之前在第一个文件中找到了该记录。否定!测试。

如果测试为真,即如果先前在第一个文件中未看到第二个文件中的当前行,则执行默认操作。没有相应块的测试的默认操作{...}是输出当前行(即,它的行为就像代码是一样!b[$0] { print })。


由于此awk脚本将第一个文件中的所有(唯一)行读取到内存中,因此运行在非常大文件。

在这些情况下,最好做类似的事情

comm -13 <( sort -u file1 ) <( sort -u file2 )

(这需要一个知道进程替换的 shell),或者只是

comm -13 file1 file2

如果文件已经排序。

这不会生成精确的与脚本相同的输出awk将输出多次出现的任何行,file2每次发生一次,而如果在输入上使用上面comm的命令则不会。sort -u

有关详细信息,请参阅comm系统手册。


解决评论中的问题:

  1. 是的,FNR是从当前输入文件读取的记录数。
  2. NR并且FNR不“属于”任何一个文件,它们只是计数器。FNR当到达文件末尾时计数器重置。
  3. 从文件中读取一行时NR和都会递增。FNRnext命令强制跳转到脚本的开头,这也会导致读取下一行。由于读取了新行,因此NR和会因此而增加。FNR
  4. 如果NR != FNR那么这意味着我们已经超越了第一个文件。FNR在到达前一个文件末尾时重置为零,但NR只是继续计数。
  5. $0是保存当前行的变量。它保存从文件中读取的完整行。$1$2持有领域当前行的值按变量值IFS(通常是任何空格)进行分割。如果当前行是hello world$0则将具有该值hello world,而$1具有该值hello并且$2具有该值world(因为该行在空格上被分割)。该脚本仅使用$0while ,您可能会将其视为$0“当前输入行的内容”。
  6. b[$0] = 1是将值分配给数组中的特定位置/索引b。位置由当前行 确定,$0分配的值为 1。这使得数组b就像一个“查找表”;如果b[i]任何特定索引为 1 i,则这意味着它在第一个输入文件中出现。
  7. !b[$0]$0如果存储在索引处的值b为零(或者未初始化),即如果b[$0]从未分配值1,即刚刚从第二个文件读取的行之前在第一个文件中没有看到,则为真。由于没有与此测试对应的动作(无块),因此执行{...}打印的默认动作。$0这具有打印第二个文件中第一个文件中不存在的每一行的效果。

相关内容