比较linux终端中的两个文件

Posted

技术标签:

【中文标题】比较linux终端中的两个文件【英文标题】:Comparing two files in linux terminal 【发布时间】:2013-01-08 04:13:42 【问题描述】:

有两个名为 "a.txt""b.txt" 的文件都有一个单词列表。现在我想检查 "a.txt" 中哪些单词是多余的,而 "b.txt" 中没有。

我需要一个高效的算法,因为我需要比较两个字典。

【问题讨论】:

diff a.txt b.txt 还不够吗? 每个文件中的单词可以出现多次吗?你能对文件进行排序吗? 我只需要那些“b.txt”中不存在而a.txt中存在的词 【参考方案1】:
diff a.txt b.txt | grep '<'

然后可以通过管道进行切割以获得干净的输出

diff a.txt b.txt | grep '<' | cut -c 3

【讨论】:

【参考方案2】:

你也可以使用:

sdiff file1 file2

在终端中并排显示差异!

【讨论】:

【参考方案3】:

为此使用 awk。测试文件:

$ cat a.txt
one
two
three
four
four
$ cat b.txt
three
two
one

awk:

$ awk '
NR==FNR                     # process b.txt  or the first file
    seen[$0]                 # hash words to hash seen
    next                     # next word in b.txt
                            # process a.txt  or all files after the first
!($0 in seen)' b.txt a.txt   # if word is not hashed to seen, output it

重复输出:

four
four

为避免重复,请将 a.txt 中每个新遇到的单词添加到 seen 哈希中:

$ awk '
NR==FNR 
    seen[$0]
    next

!($0 in seen)               # if word is not hashed to seen
    seen[$0]                 # hash unseen a.txt words to seen to avoid duplicates 
    print                    # and output it
' b.txt a.txt

输出:

four

如果单词列表以逗号分隔,例如:

$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three

你必须多跑几圈 (forloops):

awk -F, '                    # comma-separated input
NR==FNR 
    for(i=1;i<=NF;i++)       # loop all comma-separated fields
        seen[$i]
    next


    for(i=1;i<=NF;i++)
        if(!($i in seen)) 
             seen[$i]        # this time we buffer output (below):
             buffer=buffer (buffer==""?"":",") $i
        
    if(buffer!="")          # output unempty buffers after each record in a.txt
        print buffer
        buffer=""
    
' b.txt a.txt

本次输出:

four
five,six

【讨论】:

【参考方案4】:

你可以使用 linux 中的diff 工具来比较两个文件。您可以使用 --changed-group-format--unchanged-group-format 选项来过滤所需的数据。

以下三个选项可用于为每个选项选择相关组:

'%

'%>' 从 FILE2 获取行

''(空字符串)用于从两个文件中删除行。

例如:diff --changed-group-format="%

[root@vmoracle11 tmp]# cat file1.txt 
test one
test two
test three
test four
test eight
[root@vmoracle11 tmp]# cat file2.txt 
test one
test three
test nine
[root@vmoracle11 tmp]# diff --changed-group-format='%<' --unchanged-group-format='' file1.txt file2.txt 
test two
test four
test eight

【讨论】:

【参考方案5】:

另外,不要忘记mcdiff - GNU Midnight Commander 的内部差异查看器。

例如:

mcdiff file1 file2

享受吧!

【讨论】:

【参考方案6】:

如果您更喜欢 git diff 的 diff 输出样式,可以将其与 --no-index 标志一起使用来比较不在 git 存储库中的文件:

git diff --no-index a.txt b.txt

使用两个文件,每个文件包含大约 200k 文件名字符串,我对(使用内置的 timecommand)这种方法与此处的其他一些答案进行了基准测试:

git diff --no-index a.txt b.txt
# ~1.2s

comm -23 <(sort a.txt) <(sort b.txt)
# ~0.2s

diff a.txt b.txt
# ~2.6s

sdiff a.txt b.txt
# ~2.7s

vimdiff a.txt b.txt
# ~3.2s

comm 似乎是迄今为止最快的,而git diff --no-index 似乎是 diff 样式输出的最快方法。


2018-03-25 更新 实际上,您可以省略 --no-index 标志,除非您在 git 存储库中并且想要比较该存储库中未跟踪的文件。来自the man pages:

这种形式是比较文件系统上给定的两个路径。在 Git 控制的工作树中运行该命令且至少有一个路径指向该工作树之外时,或者在 Git 控制的工作树之外运行该命令时,您可以省略 --no-index 选项。

【讨论】:

【参考方案7】:

您还可以使用:colordiff:用颜色显示 diff 的输出。

关于vimdiff:它允许您通过SSH比较文件,例如:

vimdiff /var/log/secure scp://192.168.1.25/var/log/secure

摘自:http://www.sysadmit.com/2016/05/linux-diferencias-entre-dos-archivos.html

【讨论】:

【参考方案8】:

如果你安装了 vim,试试这个:

vimdiff file1 file2

vim -d file1 file2

你会发现它很棒。

【讨论】:

绝对棒极了,设计不错,很容易找出差异。天哪 你的回答很棒,但是我的老师要求我不要使用任何库函数:P 多么棒的工具!这非常有帮助。 这些颜色的含义是什么? 带颜色的代码表示它们在两个文件中不同。 @zygimantus【参考方案9】:

试试sdiff (man sdiff)

sdiff -s file1 file2

【讨论】:

【参考方案10】:

这是我的解决方案:

mkdir temp
mkdir results
cp /usr/share/dict/american-english ~/temp/american-english-dictionary
cp /usr/share/dict/british-english ~/temp/british-english-dictionary
cat ~/temp/american-english-dictionary | wc -l > ~/results/count-american-english-dictionary
cat ~/temp/british-english-dictionary | wc -l > ~/results/count-british-english-dictionary
grep -Fxf ~/temp/american-english-dictionary ~/temp/british-english-dictionary > ~/results/common-english
grep -Fxvf ~/results/common-english ~/temp/american-english-dictionary > ~/results/unique-american-english
grep -Fxvf ~/results/common-english ~/temp/british-english-dictionary > ~/results/unique-british-english

【讨论】:

您尝试过其他解决方案吗?这些解决方案之一对您有用吗?您的问题很笼统,足以吸引许多用户,但您的回答更符合我的口味……对于我的特殊情况,sdiff -s file1 file2 很有用。 @Metafaniel 我的解决方案不使用 sdiff 命令。它只使用linux内置命令来解决问题。【参考方案11】:

使用comm -13(需要排序的文件)

$ cat file1
one
two
three

$ cat file2
one
two
three
four

$ comm -13 <(sort file1) <(sort file2)
four

【讨论】:

【参考方案12】:

对它们进行排序并使用comm:

comm -23 <(sort a.txt) <(sort b.txt)

comm 比较(排序的)输入文件并默认输出三列:a 唯一的行、b 唯一的行以及两者中都存在的行。通过指定-1-2 和/或-3,您可以抑制相应的输出。因此comm -23 a b 仅列出对 a 唯一的条目。我使用&lt;(...) 语法对文件进行动态排序,如果它们已经排序,则不需要。

【讨论】:

我只使用 grep 命令添加了我自己的答案,请告诉我它更有效吗? @AliImran, comm 效率更高,因为它在一次运行中完成工作,无需将整个文件存储在内存中。由于您使用的字典很可能已经排序,因此您甚至不需要sort 他们。另一方面,使用grep -f file1 file2 会将整个file1 加载到内存中,并将file2 中的每一行与所有这些条目进行比较,这样效率要低得多。它主要用于小的、未排序的-f file1 感谢@AndersJohansson 分享“comm”命令。它确实很漂亮。我经常需要在文件之间进行外部连接,这可以解决问题。 注意换行符...我刚刚发现\n也会包含进来做对比。

以上是关于比较linux终端中的两个文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 终端中有两个正在运行的进程? (Linux 命令)

从终端杀死linux中的python解释器

linux驱动系列之ubuntu快捷键(转)

如何在linux终端上替换多个文件中的一行? [复制]

C ++只用一个命令逐行读取终端的文件流

ubuntu终端中字体颜色含义