2つのファイルがあるとしましょう
ファイル1:
Locus_1
Locus_2
Locus_3
ファイル2:
3 3 Locus_1 Locus_40 etc_849
3 2 Locus_2 Locus_94 *
2 2 Locus_6 Locus_1 *
2 3 Locus_3,Locus_4 Locus_50 *
3 3 Locus_9 Locus_3 etc_667
出力など、最初のファイルに対してgrep -F
を実行したいのみ 2番目のファイルの3列目(元のFile2
フィールドはタブで区切られています)でなければなりません:
出力:
3 3 Locus_1 Locus_40 etc_849
3 2 Locus_2 Locus_94 *
2 3 Locus_3,Locus_4 Locus_50 *
どうすればできますか?
カオスに編集:いいえ、カンマは間違いではありません。 1つの列に複数のLocus_ *を含めることができます。2番目のLocus_ *(コンマの後の1つ)がFile1
の行の1つと一致する場合も、取得します。
grep
が必要ない場合、1つの簡単な解決策はjoin
を使用することです。
_$ join -1 1 -2 3 <(sort file1) <(sort -k3 file2)
Locus_1 3 3 Locus_40 etc_849
Locus_2 3 2 Locus_94 *
Locus_3 2 3 Locus_4 Locus_50 *
_
説明:
join -1 1 -2 3
_:2つのファイルを結合します。最初のファイルでは最初の(そして唯一の)フィールドが使用され、2番目のファイルでは3番目のフィールドが使用されます。それらが等しいときに印刷されます。<(sort file1)
:join
はソートされた入力が必要です<(sort -k3 file2)
:入力は結合フィールド(ここでは3番目のフィールド)でソートする必要がありますhttps://stackoverflow.com/a/9937241/1673337 からソリューションを適応させると、(g)awkを使用して取得できます:
awk 'NR==FNR{a[$0]=1;next} {for(i in a){if($3~i){print;break}}}' File1 File2
指定された出力を提供します。
RegExを作成してgrepにフィードし、3列目のマッチングのみを満たすようにすることもできますが、この時点でawkを使用する方が理解しやすいと思います。
if($3~i){print;break}
部分は、3番目の列がFile1の行(配列aに格納されている)と一致する場合にのみ印刷を行います。残りの説明については、リンクされた投稿を参照してください。
これによりFile1の内容全体がメモリに読み込まれることに注意してください。ただし、比較の乗法的な性質のため、これが問題になるのは、ファイルが大きい場合のみです。
grep -F
オプションを使用すると、現在の行でliteral文字列anywhereが検索されます。定義により、literalは、正規表現を使用して検索をフィールド3 (TAB区切り)内のみに絞り込むことができないことを意味します。
ただし、grep -f
を使用してパターン入力を読み取ることができますfile1-ただし、正規表現のリストに変更する必要があります。以下は、bashプロセスの置換を使用してsedを使用し、grep -f
が処理できる標準正規表現のリストを生成する方法の1つです。
Basic Regular Expressionsでgrepを使用する:
grep -f <(sed 's/.*/^\\([^\t]\\+\t\\)\\{2\\}\\([^\t]\\+,\\)*&[,\t]/' file1) file2
GrepのBasic regexの場合、file1
は動的に次のように変換されます。
^\([^ ]\+ \)\{2\}\([^ ]\+,\)*Locus_1[, ]
^\([^ ]\+ \)\{2\}\([^ ]\+,\)*Locus_2[, ]
^\([^ ]\+ \)\{2\}\([^ ]\+,\)*Locus_3[, ]
[〜#〜] or [〜#〜]:grep -E
を拡張正規表現とともに使用すると、コードを視覚的に簡略化して、 grep
とsed
の両方にほとんどのバックスラッシュが必要
grep -Ef <(sed 's/.*/^([^\t]+\t){2}([^\t]+,)*&[,\t]/' file1) file2
Grepの拡張正規表現の場合、file1
は動的に次のように変換されます。
^([^ ]+ ){2}([^ ]+,)*Locus_1[, ]
^([^ ]+ ){2}([^ ]+,)*Locus_2[, ]
^([^ ]+ ){2}([^ ]+,)*Locus_3[, ]
出力(両方の場合):
3 3 Locus_1 Locus_40 etc_849
3 2 Locus_2 Locus_94 *
2 3 Locus_3,Locus_4 Locus_50 *
-f
および-F
は、file1
が大きい間、物事を劇的に遅くする可能性があることに注意してください。
grep -P
_ソリューション:_regexp=$( echo -n '('; < File1 tr '\n' '|' | sed 's/|$//'; echo ')' )
grep -P "^[^\s]+\s+[^s]+\s+([^\s]*,)*$regexp" File2
_
_3 3 Locus_1 Locus_40 etc_849
3 2 Locus_2 Locus_94 *
2 3 Locus_3,Locus_4 Locus_50 *
_
_File1
_に特殊な正規表現文字が含まれている可能性がある場合は、それらをエスケープする必要があります。
_regexp_escape() { Ruby -pe '$_ = Regexp.escape($_.chomp("\n")) + "\n"'; }
regexp=$( echo -n '('; < File1 regexp_escape | tr '\n' '|' | sed 's/|$//'; echo ')' )
grep -P "^[^\s]+\s+[^s]+\s+([^\s]*,)*$regexp" File2
_
2行目は、_(Locus_1|Locus_2|Locus_3)
_などの文字列を作成します。そして
"^[^\s]+\s+[^s]+\s+([^\s]*,)*"
手段:
[Word] [whitespace(s)] [Word] [whitespace(s)] [(optional Word followed by comma) zero or arbitrarily many times]
( t=$(printf \\t) ntt=[^$t]*$t ntc=[^$t,]*
### ^just makes it easy regardless of your sed version.
sed -ne"s/..*/^($ntt){2}($ntc,)*&(,$ntc)*$t/p" |
grep -Ef- ./File2
) <File1
3 3 Locus_1 Locus_40 etc_849
3 2 Locus_2 Locus_94 *
2 3 Locus_3,Locus_4 Locus_50 *
これにより、先行する($ntc,)*
グループの数や後続の(,$ntc)*
グループの数に関係なく、File2の3番目の列のFile1の行に一致します。ただし、File1の検索文字列にメタ文字がないことに依存します。 File1にメタ文字がある可能性がある場合は、まずそれをクリーンアップする必要があります。
( t=$(printf \\t) ntt=[^$t]*$t ntc=[^$t,]*
sed -ne's/[]?{(^$|*.+)}\[]/\\&/g' \
-e"s/..*/^($ntt){2}($ntc,)*&(,$ntc)*$t/p" |
grep -Ef- ./File2
) <File1
列を「grep」するにはawk
が最適なツールです
BEGIN { f="Locus_2" }
$3==f { print $0; }
file1をループできます
for x in `cat File1`
do awk -v X="$x" '$3~X { print $0 }' <File2
done
。