私は次のことをしようとしました。
- 3つの数字列を持つファイルがあり、1つの数字列を持つ小さなファイルと比較して一致する行を印刷したいと思いました。
- 私は使用していますが、
grep -F
常に一致しない行を提供します。
答え1
私の考えでは、101
より小さなファイルが含まれているときに一致する10
ものと同じものが表示されます。これは、10が101の部分文字列であるためです。
デフォルトファイルにフィールドが1つしかない場合は、-x
正確な一致のためにgrepオプションを使用できます。例えば
grep -x -F -f smallerfile.txt mainfile.txt
3つのフィールドがあるため、各フィールドを個別に一致させる必要があるため、perlやawkなどを使用する必要があります。たとえば、awkを使用すると、次のようになります。
$ cat smallerfile.txt
1
10
25
152
$ cat mainfile.txt
1 2 3
5 10 15
10 11 12
100 101 102
150 151 152
250 255 260
$ awk 'FNR == NR { nums[$1]++ ; next }
$1 in nums || $2 in nums || $3 in nums' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152
しかし、3つ以上のフィールドをチェックする必要がある場合は、スクリプトを作成または更新するのが面倒です。これを回避するには、各フィールド(数に関係なく)を繰り返し、そのうちの1つの値が配列にあることを確認するawk関数を作成しますnums
。例えば
$ awk 'function check_all_fields() {
for (i=1; i<=NF; i++) {
if ($i in nums) return 1
}
return 0
}
FNR == NR { nums[$1]++ ; next }
check_all_fields()' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152
ご覧のとおり、出力は最初のバージョンと同じです。
check_all_fields()
関数が入力行で一致するフィールドを確認すると、1(true)が返されます。現在の行に1がまったく表示されない場合は0(false)を返します。
答え2
近所を活用して検索文字列をsed
案内する次のアプローチを使用してこれを行うことができます。grep
sed -e 's/.*/\\<&\\>/' f1 | grep -Ef - f3col
出力:-
1 2 3
5 10 15
10 11 12
150 151 152
awk
図のように操作できます。まず、a[...]
単一の列ファイルの列に基づく連想配列を形成します。次に、3列ファイルの各行でフラグを初期化p
し、単一の列ファイルのフィールドに一致するデータがある場合、フラグをインクリメントします。その後、for ループの終了時にフラグが少なくとも 1 回増加した場合、条件付きでレコードを印刷します。
awk '
NR==FNR{a[$1];next}
{
for (p=i=1; i<=NF; i++) if ($i in a) p++
}p>1
' f1 f3col
python
データ構造自体は、set
以下のようにセットの交差集合が空でない場合を印刷する実装をサポートします。
python3 -c 'import sys
file1,file2 = sys.argv[1:]
with open(file1) as f1, open(file2) as f2:
s1 = { _.rstrip() for _ in f1 }
for _ in f2:
s2 = set(_.rstrip().split())
if bool(s2 & s1):
print(_,end="")
' f1 f3col
構文を使用して、POSIX sed
まず単一の列ファイルを使用してPOSIX sedコードを生成し、それを3列ファイルに適用します。
sed -e '
h;G;G
s/.*/^&$/
s|\n| /b&/ |g
s|.*|/&/b|;$a\
d
' f1 | sed -f - f3col
perl
これはいくつかの方法で行うことができます。
perl -lane '
@A || chomp(@A=<STDIN>);
for my $f (@F) {
print,last if grep { $f == $_ } @A;
}
' f3col < f1
perl -MList::Util=any -lane '
chomp(@A=<STDIN>) if !@A;
print if
any {
my $f = $_;
any { $_ == $f } @A;
} @F;
' f3col < f1