Shell:查找多个文件中的匹配行

时间:2012-09-03 11:26:06

标签: grep

我正在尝试使用shell脚本(以及“单行”)来查找大约50个文件之间的任何公共行。 修改:注意我正在寻找所有文件中出现的一行(行)

到目前为止,我已经尝试了grep grep -v -x -f file1.sp *,它只是匹配所有其他文件中的文件内容。

我也尝试了grep -v -x -f file1.sp file2.sp | grep -v -x -f - file3.sp | grep -v -x -f - file4.sp | grep -v -x -f - file5.sp等...但我相信使用要搜索的文件作为STD搜索而不是匹配的模式。

有人知道怎么用grep或其他工具吗?

我不介意运行需要一段时间,我必须在大约500个文件中添加几行代码,并希望在每个文件中找到一条公共行,以便插入'after'(它们原本只是一个文件中的c& p所以希望有一些共同的行!)

感谢您的时间,

4 个答案:

答案 0 :(得分:3)

当我第一次阅读本文时,我以为你试图找到'任何共同的线'。我把它当作“找到重复的行”的意思。如果是这种情况,以下内容就足够了:

sort *.sp | uniq -d

重新阅读您的问题后,您似乎正在尝试查找“出现在所有文件中”的行。如果是这种情况,您需要知道目录中的文件数:

find . -type f -name "*.sp" | wc -l

如果这返回数字50,则可以使用awk,如下所示:

WHINY_USERS=1 awk '{ array[$0]++ } END { for (i in array) if (array[i] == 50) print i }' *.sp

你可以整合这个过程并写一个单行代码:

WHINY_USERS=1 awk -v find=$(find . -type f -name "*.sp" | wc -l) '{ array[$0]++ } END { for (i in array) if (array[i] == find) print i }' *.sp

答案 1 :(得分:2)

结合这两个答案(ans1ans2)我认为您可以在不对文件进行排序的情况下获得所需的结果:

#!/bin/bash
ans="matching_lines"

for file1 in *
do 
    for file2 in *
        do 
            if  [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
                echo "Comparing: $file1 $file2 ..." >> $ans
                perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
            fi
         done 
done

只需保存它,赋予它执行权限(chmod +x compareFiles.sh)并运行它。它将获取当前工作目录中存在的所有文件,并将在“matching_lines”文件中进行全对比比较结果。

有待改进的地方:

  • 跳过目录
  • 避免两次比较所有文件(file1 vs file2和file2 vs file1)。
  • 可能在匹配字符串
  • 旁边添加行号

希望这有帮助。

最佳,

Alan Karpovsky

答案 2 :(得分:1)

this answer。我原来虽然diff听起来像你要求的,但这个答案似乎更合适。

答案 3 :(得分:1)

old,bash answer(O(n);打开2 * n个文件)

从@ mjgpy3回答,您只需要进行for循环并使用comm,如下所示:

#!/bin/bash

tmp1="/tmp/tmp1$RANDOM"
tmp2="/tmp/tmp2$RANDOM"

cp "$1" "$tmp1"
shift
for file in "$@"
do
    comm -1 -2 "$tmp1" "$file" > "$tmp2"
    mv "$tmp2" "$tmp1"
done
cat "$tmp1"
rm "$tmp1"

保存在comm.sh中,将其设为可执行文件,然后调用

./comm.sh *.sp 

假设您的所有文件名都以.sp结尾。

更新后的答案python,只打开每个文件一次

看看其他答案,我想给每个文件打开一次而不使用任何临时文件,并支持重复的行。另外,让我们并行处理文件。

你去(在python3中):

#!/bin/env python
import argparse
import sys
import multiprocessing
import os

EOLS = {'native': os.linesep.encode('ascii'), 'unix': b'\n', 'windows': b'\r\n'}

def extract_set(filename):
    with open(filename, 'rb') as f:
        return set(line.rstrip(b'\r\n') for line in f)

def find_common_lines(filenames):
    pool = multiprocessing.Pool()
    line_sets = pool.map(extract_set, filenames)
    return set.intersection(*line_sets)

if __name__ == '__main__':
    # usage info and argument parsing
    parser = argparse.ArgumentParser()
    parser.add_argument("in_files", nargs='+', 
            help="find common lines in these files")
    parser.add_argument('--out', type=argparse.FileType('wb'),
            help="the output file (default stdout)")
    parser.add_argument('--eol-style', choices=EOLS.keys(), default='native',
            help="(default: native)")
    args = parser.parse_args()

    # actual stuff
    common_lines = find_common_lines(args.in_files)

    # write results to output
    to_print = EOLS[args.eol_style].join(common_lines)
    if args.out is None:
        # find out stdout's encoding, utf-8 if absent
        encoding = sys.stdout.encoding or 'utf-8'
        sys.stdout.write(to_print.decode(encoding))
    else:
        args.out.write(to_print)

将其保存到find_common_lines.py,然后致电

python ./find_common_lines.py *.sp

使用--help选项的更多使用信息。