複数のファイル(すべてのファイルに共通の行)の共通部分を見つけるための簡単なスクリプトを書きたいので、ここでいくつか読んだ後(- link )bashスクリプトを書き込もうとしましたが、残念ながら失敗しました。私は何が間違っているのですか?
RES=$(comm -12 ${1} ${2})
for FILE in ${@:3}
do
RES=$(comm -12 $FILE ${RES})
done
おそらくparallel
またはxargs
を使用してこれを実装する方法について他に提案はありますか?
RES
を逆参照する場合:
comm $FILE ${RES}
RES
の内容が${RES}
に置き換わります。ただし、comm
はファイル名を引数として想定しているため、たとえば$RES
にhello
comm
が含まれている場合、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
関数は再帰的なアプローチを可能にします
f() {
if (($# == 1))
then
cat $1;
return;
fi
comm -12 $1 <(f "${@:2}")
}
f file1 file2 file3 file4 file5...
問題は、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
_
parallel
もxargs
も、comm
も必要ありません。機能を試す
$ intersection() { sort $@ | uniq -c | sed -n "s/^ *$# //p"; }
$ intersection file[1-3]
line2
line4