5

シェルスクリプト(「ワンライナー」)を使用して、約50個のファイル間の共通行を見つけようとしています。 編集:すべてのファイルに表示される行(行)を探していることに注意してください

grep -v -x -f file1.sp *これまでのところ、他のすべてのファイルでそのファイルの内容と一致するgrepを試しました。

私も試してみました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」を挿入する必要がありました (最初は1つのファイルからc&pするだけなので、共通の行がいくつかあることを願っています!)

御時間ありがとうございます、

4

4 に答える 4

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
于 2012-09-03T23:06:29.730 に答える
2

古い、bashの回答(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は、各ファイルを1回だけ開きます

他の答えを見て、一時ファイルを使用せずにファイルごとに1回開き、重複行をサポートするものを提供したいと思いました。さらに、ファイルを並行して処理しましょう。

ここに行きます(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オプションでより多くの使用法情報。

于 2012-09-04T00:07:09.773 に答える
2

この 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」ファイルに結果を残して全対全比較を行います。

改善すべき点:

  • ディレクトリをスキップ
  • すべてのファイルを 2 回比較することは避けてください (file1 と file2 および file2 と file1)。
  • たぶん、一致する文字列の横に行番号を追加します

お役に立てれば。

一番、

アラン・カルポフスキー

于 2013-11-08T14:28:04.423 に答える
1

この回答を参照してください。私はもともとdiffあなたが求めていたもののように聞こえましたが、この答えははるかに適切なようです.

于 2012-09-03T11:39:53.590 に答える