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第一个文件FILENUM
是n。
读取每一行时,计算已在其中看到该行的文件数(但仅当在之前的每个文件中都已看到该行时,您才需要费心执行此操作)。
当没有更多输入可供读取时,打印所有文件中已看到的所有行。
警告:与此处发布的几个解决方案一样,这个解决方案也有一个弱点。根据问题,如果任何输入文件为空,则应该有根本没有输出。但是,由于 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