web-dev-qa-db-ja.com

複数のファイル(必ずしも2つのファイルである必要はありません)の共通部分を見つける方法は?

複数のファイル(すべてのファイルに共通の行)の共通部分を見つけるための簡単なスクリプトを書きたいので、ここでいくつか読んだ後(- link )bashスクリプトを書き込もうとしましたが、残念ながら失敗しました。私は何が間違っているのですか?

RES=$(comm -12 ${1}  ${2})

for FILE in ${@:3}
do
    RES=$(comm -12 $FILE  ${RES})
done

おそらくparallelまたはxargsを使用してこれを実装する方法について他に提案はありますか?

2
JammingThebBits

RESを逆参照する場合:

comm $FILE  ${RES}

RESの内容が${RES}に置き換わります。ただし、commはファイル名を引数として想定しているため、たとえば$REShellocommが含まれている場合、helloという名前のファイルを開こうとします。

代わりに、一時ファイルを使用して、プロセス中に共通の行を保存できます。

tmp=$(mktemp --tmpdir)
tmp2=$(mktemp --tmpdir)
comm -12 ${1}  ${2} >$tmp

for FILE in ${@:3}
do
    comm -12 $FILE  $tmp >$tmp2
    rm $tmp 
    mv $tmp2 $tmp   
done

cat $tmp 
rm $tmp
1
Erwan

関数は再帰的なアプローチを可能にします

f() {
     if (($# == 1))
     then
         cat $1;
         return;
     fi
     comm -12 $1 <(f "${@:2}")
}

f file1 file2 file3 file4 file5...
2
iruvar

問題は、commが2つのファイルを必要とし、_$RES_が変数であるということです。

しかし、チートで、プロセス置換を使用してファイルのように見せることができます。

_#!/bin/bash

RES=$(comm -12 ${1}  ${2})

for FILE in ${@:3}
do
    RES="$(comm -12 $FILE  <(printf %s "${RES}"))"
done

printf %s "$RES"
_

これは元のファイルとほとんど同じですが、<(...)構造体を使用してコマンドを実行し、それをファイル名として使用します。

したがって、次の3つのファイルがある場合:

_a:line1
a:line2
a:line3
a:line4
b:line2
b:line4
b:line6
c:line2
c:line4
c:line8
_

それらを比較することができます:

_% ./allcomp a b c
line2
line4
_
0
Stephen Harris

parallelxargsも、commも必要ありません。機能を試す

$ intersection() {  sort $@ | uniq -c | sed -n "s/^ *$# //p"; }
$ intersection file[1-3]
line2
line4
0
RudiC