【问题标题】:How can I find lines in one file but not the other using bash scripting?如何使用 bash 脚本在一个文件中找到行而不在另一个文件中找到行?
【发布时间】:2015-02-21 22:08:53
【问题描述】:

想象一下文件 1:

#include "first.h"
#include "second.h"
#include "third.h"

// more code here
...

想象一下文件 2:

#include "fifth.h"
#include "second.h"
#include "eigth.h"

// more code here
...

我想获取文件 2 中包含的标题,但不是文件 1 中的标题,只有那些行。 因此,当运行时,文件 1 和文件 2 的差异将产生:

#include "fifth.h"
#include "eigth.h"

我知道如何在 Perl/Python/Ruby 中执行此操作,但我想在不使用其他编程语言的情况下完成此操作。

【问题讨论】:

  • 更多方法来做同样的事情,看看这个BashFAQ。请记住,由于所有这些解决方案都进行基于行的模式匹配,因此您必须确保在任何地方都以相同的方式格式化包含行。示例:#include 将不匹配 # include"first.h" 将不匹配子目录中的 "../first.h" 等。

标签: bash shell


【解决方案1】:

这是一个单行,但不保留顺序:

comm -13 <(grep '#include' file1 | sort) <(grep '#include' file2 | sort)

如果需要保留订单:

awk '
  !/#include/ {next} 
  FILENAME == ARGV[1] {include[$2]=1; next} 
  !($2 in include)
' file1 file2

【讨论】:

【解决方案2】:

如果可以使用临时文件,试试这个:

grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep include

这个

  • file1.h 中提取所有包含并将它们写入文件/tmp/x
  • 使用此文件从file2.h 中获取未包含在此列表中的所有行
  • file2.h 的其余部分中提取所有包含

不过,它可能无法正确处理空格等方面的差异。

编辑: 为了防止误报,最后一个 grep 使用不同的模式(感谢 jw013 提到这一点):

grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep "^#include"

【讨论】:

  • 也许将最后一个 grep 模式更改为 '^#include',除非您还想查看碰巧使用“包含”一词的随机代码行
  • 当 greping 匹配行时,您应该使用选项:-F 用于“固定字符串”(非正则表达式)模式,-x 用于“整行”匹配。此外,临时文件不是绝对必要的,您可以使用-f - 从标准输入中获取模式文件。生成的命令变为:grep '^#include' file1.h | grep -f - -vFx file2.h | grep '^#include'
【解决方案3】:

此变体需要带有-f 选项的fgrep。 GNU grep(即任何 Linux 系统,然后是一些)应该可以正常工作。

# Find occurrences of '#include' in file1.h
fgrep '#include' file1.h |
# Remove any identical lines from file2.h
fgrep -vxf - file2.h |
# Result is all lines not present in file1.h.  Out of those, extract #includes
fgrep '#include'

这不需要任何排序,也不需要任何明确的临时文件。理论上,fgrep -f 可以在幕后使用临时文件,但我相信 GNU fgrep 不会。

【讨论】:

  • POSIX 指定 -f,因此任何符合 POSIX 的 grep 都应该拥有它。
【解决方案4】:

如果不需要单独使用 Bash 来实现目标(即,可以使用外部程序),则使用来自 moreutilscombine

combine file1 not file2 > lines_in_file1_not_in_file2

【讨论】:

    【解决方案5】:

    猫 $file1 $file2 | grep '#include' |排序 | uniq -u

    【讨论】:

    • 这将列出文件 1 或文件 2 独有的 #include 行。我认为你想要 cat $file1 $file1 $file2 | grep '#include' | sort | uniq -u,重复 file1 以便其 #include 行加倍,然后将被 uniq -u 过滤。
    • 而且由于grep 可以读取多个输入文件,您可以使用grep -h 并取消(仅适度无用的)cat
    猜你喜欢
    • 2018-03-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 2021-04-14
    相关资源
    最近更新 更多