识别文件中的重复行而不删除它们?

识别文件中的重复行而不删除它们?

我的参考资料是一个文本文件,其中包含一长串条目,每个条目都有两个(或更多)字段。

第一列是参考文献的 URL;第二列是标题,根据条目的制作方式可能会有所不同。第三列也是一样,可能会出现,也可能不存在。

我想识别但不删除第一个字段(引用 URL)相同的条目。我知道,sort -k1,1 -u但这会自动(非交互地)删除除第一个匹配项之外的所有匹配项。有没有办法让我知道,以便我可以选择保留哪些匹配项?

下面的三行代码中,有相同的第一个字段(http://unix.stackexchange.com/questions/49569/),我想保留第 2 行,因为它有附加标签(sort、CLI),并删除第 1 行和第 3 行:

http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

有没有程序可以帮助识别此类“重复”?然后,我可以通过亲自删除第 1 行和第 3 行来手动清理?

答案1

这是一个经典问题,可以用命令解决uniquniq可以检测重复连续的行并删除重复项 ( -u, --unique) 或仅保留重复项 ( -d, --repeated)。

由于重复行的顺序对你来说并不重要,你应该先对其进行排序。然后使用它uniq仅打印唯一的行:

sort yourfile.txt | uniq -u

还有一个-c( --count) 选项,用于打印该选项的重复项数-d。有关详细信息,请参阅手册页uniq


如果您确实不关心第一个字段之后的部分,您可以使用以下命令来查找重复的键并打印其每个行号(附加另一个| sort -n以使输出按行排序):

 cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D

由于您想要查看重复的行(使用第一个字段作为键),因此您不能直接使用uniq。使自动化变得困难的问题是标题部分各不相同,但程序无法自动确定哪个标题应被视为最后一个标题。

这是一个 AWK 脚本(将其保存到script.awk),它将您的文本文件作为输入并打印所有重复的行,以便您可以决定删除哪些行。(awk -f script.awk yourfile.txt

#!/usr/bin/awk -f
{
    # Store the line ($0) grouped per URL ($1) with line number (NR) as key
    lines[$1][NR] = $0;
}
END {
    for (url in lines) {
        # find lines that have the URL occur multiple times
        if (length(lines[url]) > 1) {
            for (lineno in lines[url]) {
                # Print duplicate line for decision purposes
                print lines[url][lineno];
                # Alternative: print line number and line
                #print lineno, lines[url][lineno];
            }
        }
    }
}

答案2

如果我理解你的问题,我认为你需要类似以下内容的内容:

for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done

或者:

for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done

file.txt包含您感兴趣的数据的文件在哪里?

在输出中,您将看到行数以及第一个字段出现两次或更多次的行数。

答案3

如果我没看错的话,你所需要的只是

awk '{print $1}' file | sort | uniq -c | 
    while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done

这将打印出包含重复项的行号和行本身。例如,使用此文件:

foo bar baz
http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
bar foo baz
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
baz foo bar
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

它将产生以下输出:

2:http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
4:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
6:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

要仅打印行号,你可以这样做

awk '{print $1}' file | sort | uniq -c | 
 while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1

并且只打印该行:

awk '{print $1}' file | sort | uniq -c | 
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-

解释:

awk脚本仅打印文件的第一个空格分隔字段。用于$N打印第 N 个字段。sort对其进行排序并uniq -c计算每行的出现次数。

然后将其传递给while循环,该循环将出现的次数保存为,$num并将行保存为,$dupe如果$num大于一(因此至少重复一次),它将在文件中搜索该行,并使用-n打印行号。--表示grep后面的内容不是命令行选项,在$dupe以 开头时很有用-

答案4

请参阅以下排序file.txt

addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/ ::: C2P per-element
addons.mozilla.org/en-us/firefox/addon/prospector-oneLiner/ ::: OneLiner
askubuntu.com/q/21033 ::: What is the difference between gksudo and gksu?
askubuntu.com/q/21148 ::: openoffice calc sheet tabs (also askubuntu.com/q/138623)
askubuntu.com/q/50540 ::: What is Ubuntu's Definition of a "Registered Application"?
askubuntu.com/q/53762 ::: How to use lm-sensors?
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
stackoverflow.com/q/4594319 ::: bash - shell replace cr\lf by comma
stackoverflow.com/q/4594319 ::: shell replace cr\lf by comma
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence - Ubuntu Wiki
www.youtube.com/watch?v=1olY5Qzmbk8 ::: Create new mime types in Ubuntu
www.youtube.com/watch?v=2hu9JrdSXB8 ::: Change mouse cursor
www.youtube.com/watch?v=Yxfa2fXJ1Wc ::: Mouse cursor size

因为列表很短,所以我可以看到(排序后)有三组重复项。

然后,例如,我可以选择保留:

askubuntu.com/q/53762 ::: How to use lm-sensors?

而不是

askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors

但对于较长的列表,这将很困难。根据两个答案,一个建议uniq,另一个建议cut,我发现此命令给出了我想要的输出:

$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$

相关内容