2つのファイルがあります。
ファイル1:
ABA
FFR
HHI
HAB
ファイル2:
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
file1 の各行は、file2 の対応する行の先頭で繰り返されるパターンです。 file1で繰り返されるパターンではなく、file2の各行部分を取得したいと思います。
希望の出力:
TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC
私はこのループを使用しようとしています:
while read -r line
do
grep -v "$line{1,}" file2.txt
done < file1.txt
しかし、私は次のような結果を得ます。
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
答え1
ABA
変数にegを使用すると、grep -v "$line{1,}"
grepにパターンが与えられます。つまり、1つ、1つ、および少なくとも1つをABA{1,}
探します。最後の反復は重要ではありません。それ以降は何もないので、1回の繰り返しでもマッチします。A
B
A
ABA
さて、デフォルトでは、grepは、次のように計算された反復をバックスラッシュで書く必要がある基本正規表現(BRE)を使用することを除いてください。拡張正規表現 (ERE) では 1 回以上の反復が発生しますが、BRE ではリテラル文字 4 つ (一般文字でもあります) です。\{n,m\}
{1,}
+
+
ただし、grepは内容全体を印刷します。ワイヤー一致または-v
一致しません。行の一部を削除しません。 (grep -o
一致する部分だけを印刷する場合を除いては適用されないと思います-v
。)また、そのループを通して次grep
のようになります。みんなパターンごとに行があるので、file2
コンテンツは何度も繰り返されます。
各反復の各入力から1行を読み取るループが必要です。シェルで実行できますが、非常に遅いです。 AWKのような方が良いです。たとえば、次のようになります。
$ awk '{getline pat < "file1"; sub("^(" pat ")*", ""); print}' file2
TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC
AWKプログラムは、行(およびコマンドラインで提供されている他のファイル)を通して暗黙的に繰り返されます。ここではfile2
、各反復で明示的に1行を読みます。file1
次に、現在の行に一致する"^(" pat ")*"
同様のパターンを構成し、それを空の文字列に置き換えます。^(ABA)*
これにより、行からパターンの追加インスタンスが削除されず、たとえばにABAABAFOOABABAR
なりますFOOABABAR
。その項目も削除するにはに変更しますgsub("(" pat ")*", "");
。
答え2
使用されたソリューションは、awk
各行の対応する行から繰り返されるパターンを削除します。file1
file2
awk 'NR==FNR { pattern[NR]="^(" $0 ")*"; next } { sub(pattern[FNR], ""); print }' file1 file2
説明する:
NR==FNR
最初のファイルのみが一致する条件です。pattern[NR]="^(" $0 ")*";
文字列でパターンを構成し、現在の行番号をインデックスとして配列に追加します。ABA
-> =^\(ABA\)*
行の先頭に繰り返される文字列の数。ABA
next
すべての追加処理をスキップします。これにより、次の操作は2番目(および後続)のファイルにのみ適用されます。sub(pattern[FNR], "")
現在の行番号を空の文字列に置き換えるパターンprint
(修正された)行を印刷してください
考えられる解決策はこれを使用して、すべての行のすべてのパターンをawk
削除します。file1
file2
awk 'NR==FNR { pattern[count++]="^(" $0 ")*"; next } { for(i = 0; i < count; i++) sub(pattern[i], ""); print }' file1 file2
説明する:
NR==FNR
最初のファイルのみが一致する条件です。pattern[count++]="^(" $0 ")*";
文字列でパターンを整理し、それを配列に追加します。ABA
-> =^(ABA)*
行の先頭に繰り返される文字列の数。処理された行数。ABA
count
file1
next
すべての追加処理をスキップします。これにより、次の操作は2番目(および後続)のファイルにのみ適用されます。for(i = 0; i < count; i++)
すべてのパターンを循環します。sub(pattern[i], "")
パターンを空の文字列に置き換えるprint
(修正された)行を印刷してください
答え3
while read
-bash-loop メソッドによると、sed
次の手法を実装できます。
#!/bin/bash
i=0
while read pat ; do
((i++))
sed -n "${i}s/^\($pat\)\{1,\}//g;${i}p" file2
done < file1
「繰り返しパターン」の説明は少し混乱しています。少なくとも2回は現れるべきだと思います。たとえば、\{2,\}
私はそれがより適切であると感じるでしょう。
答え4
それだけです、友達:
challenge.sh
#!/bin/bash
readarray -t searchStrs < file1.txt
linesInFile=$((${#searchStrs[@]} - 1))
line=0
while [ ${line} -le ${linesInFile} ]
do
srchStr=$(echo ${searchStrs[$line]})
result=$(grep -E "^${srchStr}" file2.txt | sed "s@${srchStr}@@g")
line=$((${line} + 1))
echo ${result}
done
./challenge.sh
TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC
cat file2.txt
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC