只显示所有文本文件中至少一次的行

只显示所有文本文件中至少一次的行

a.txt

cat a.txt
a
b
x
c

b.txt

cat b.txt
d
e
a
f

q:

SOMEMAGICK *.txt
a

问:如何仅显示所有 *.txt 文件中的行?

答案1

怎么样

cat *.txt | sort | uniq -c | egrep "^ +$(ls -1 *.txt | wc -l) "

然后为了减少出现次数,您可以添加......

cat *.txt | sort | uniq -c | egrep "^ +$(ls -1 *.txt | wc -l) " | sed -re 's/^ +[0-9]+ //'

根据 @Stephane 的评论,如果一行在单个文件中多次出现,则上述内容将不起作用。在这里,我首先对每个文件进行排序和唯一化以避免这种情况:

for f in *.txt; do sort -u $f > $f.uniqd; done
cat *.uniqd | sort | uniq -c | egrep "^ +$(ls -1 *.uniqd | wc -l) " | sed -re 's/^ +[0-9]+ //'

虽然现在已经不再是一句台词了。 :)

答案2

awk 'FNR == 1 { FILENUM++ }
     SEEN[$0] == FILENUM - 1 { SEEN[$0] = FILENUM }
     END { for (s in SEEN) if (FILENUM == SEEN[s]) print s }' *.txt

解释

当读取每个文件的第一行时,递增FILENUM,这样在读取时n第一个文件FILENUMn

读取每一行时,计算已在其中看到该行的文件数(但仅当在之前的每个文件中都已看到该行时,您才需要费心执行此操作)。

当没有更多输入可供读取时,打印所有文件中已看到的所有行。

警告:与此处发布的几个解决方案一样,这个解决方案也有一个弱点。根据问题,如果任何输入文件为空,则应该有根本没有输出。但是,由于 awk 是面向行的工具,因此它会忽略空文件。也就是说,对于空文件,FNR == 1 { FILENUM++ }无法增加。FILENUM

使用 GNU awk,可以使用以下命令修复此错误ARGIND内置变量。

gawk 'SEEN[$0] == ARGIND - 1 { SEEN[$0] = ARGIND }
      END { for (s in SEEN) if (ARGIND == SEEN[s]) print s }' *.txt

答案3

使用 GNU awk

awk '{
      x[$0][FILENAME]
     }
     END{
      num_files=ARGC-1;
      for (b in x)
       if (length(x[b]) == num_files) 
        print b
     }' a.txt b.txt c.txt

答案4

我喜欢使用更简单的解决方案join

join <(sort a.txt) <(sort b.txt)

这确实适用于您的两个输入文件,但在包含空格的行上可能不会按您的预期运行,它还会多次输出重复的行。

要解决第二个问题,只需

join <(sort a.txt) <(sort b.txt) | uniq

第一个有点复杂,但我用标志作了一些欺骗-t,使用不出现的字符作为字段分隔符:

$ cat a.txt 
This test
foo bar
does work
$ cat b.txt 
This is a test
foo does not work
does work
$ join <(sort a.txt) <(sort b.txt) | uniq
does work work
foo bar does not work
This test is a test
$ join -t : <(sort a.txt) <(sort b.txt) | uniq
does work

相关内容