文字列の入力ファイルを読み取り、一致させてその場で変更するにはどうすればよいですか?

文字列の入力ファイルを読み取り、一致させてその場で変更するにはどうすればよいですか?

文字列/ファイル名が別々の行にあるテキストファイルがあります。例えば、filename.txtファイル名が何百もあります。

ABC123_S386_R1_001
JKL345_S441_R1_001
filename9000_S587_R1_001

文字列/ファイル名と追加データを含む別のテキスト ファイル (例results.txt:

>ABC123_S386_R1_001 
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>JKL345_S441_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>abc7890_S387_R1_001  
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>filename9000_S587_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN

現在、 のすべてのファイル名filename.txtが に存在するわけではなく、順序も正しくありません。からresults.txtまでのすべてのファイル名にプレフィックスを挿入したいのですが、他のファイル名には挿入したいわけではありません。filename.txtresults.txt

文字列の入力ファイルを読み取り、別のファイルと照合して一致を変更するにはどうすればよいですか?

以前は、 を使って個々のファイル名を照合しsequence.txt、その行番号を取得し、sed行番号と一緒に を使って 1 行または行ブロックを変更していました。

私が望む出力は次のようになります

>h-19/US/CA-ABC123_S386_R1_001 
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>h-19/US/CA-JKL345_S441_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>abc7890_S387_R1_001  
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>h-19/US/CA-filename9000_S587_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN

h-19/US/CA-すべての一致に追加したいサフィックスはどこにありますか。

編集:>変更する必要があるすべての文字列の最初の文字です。ファイル名の前には文字がなく>、ファイル名の後に末尾の空白もありません。

答え1

関連する行にresults.txtファイル名の後に空白が含まれていないと仮定すると、次のawkプログラムは動作します。

awk -v prefix="h-19/US/CA-" 'NR==FNR{fnames[$1]; next} \
    /^>/{name=substr($0,2); if (name in fnames) {sub(/^>/, ">" prefix)} }1' filenames.txt results.txt
  • これは最初に解析しfilenames.txt、次に を実行しますresults.txt
  • 解析中filenames.txt(FNRファイルごとの行カウンタ はグローバル行カウンタ と等しいNR) は、すべてのファイル名 (行の唯一のフィールド) を配列 に登録しますfnamesが、実行はすぐに次の行にスキップされます。
  • 解析中に、results.txt行が で始まっているかどうかを確認します>。 で始まっている場合は、その文字に続く部分文字列 ( に一時的に格納されているname) が の「配列インデックス」内に見つかるかどうかを確認しますfnames。 見つかった場合は、 を使用してsub()先頭を+ プレフィックス>に置き換え、 ( ディレクティブを介して) に変数として渡します。>awkprefix-v
  • 一見「迷子」のように見えるものは、すべての可能な変更を含む現在の行を印刷するように1指示しますawk(ただし、results.txt最初のファイルの処理中にその部分に到達しないためのみです)。

awk単独ではファイルをその場で変更できないため、一時ファイルで作業する必要があることに注意してください。ただし、GNU Awk の十分に新しいバージョン (> 4.1.0) をお持ちの場合は、inplace拡張機能を使用できます。もちろん、その場合はファイルのオプションをオフにする必要がありますfilenames.txt

awk -i inplace -v prefix=" ... " ' ... ' inplace=0 filenames.txt inplace=1 results.txt

これにより、 のインプレース編集がオフになりfilenames.txt、 のインプレース編集が再びオンになりますresults.txt

答え2

sedホールドスペース内のファイル名を収集し、すべての行をチェックしてresults.txt一致するものを探し、変更する行をフィルタリングできます。

sed -e '1,/^$/{H;1h;d;}' -e 'G;/^>\(.*\).*\n\1\n/s_^>_>h-19/US/CA-_;P;d' filename.txt <((echo)) results.txt
  • <((echo))ファイル間に空行を渡すので、1,/^$/最初のファイルのすべての行(および空行)がアドレス指定されます。
  • これらの行はホールドスペースに追加され、H;1h;d1hホールドスペースが改行で始まるのを避けて)で削除されます。
  • Gホールドスペースを のすべての行に追加しresult.txt/^>\(.*\).*\n\1\n/で始まる行>と、ホールドスペース内の改行で囲まれたファイル名の文字列に一致します。
  • s_^>_>h-19/US/CA-_これらの行の置き換えは
  • P;dは、付加されたジャンクを除いた最初の行だけを出力します。s/\n.*//代わりに次のようにすることもできます。

答え3

perl入力ファイルのインプレース編集に使用します:

pfx='h-19/US/CA-' \
perl -pi -e '
  BEGIN { %h = map { tr/\n//dr => $ENV{pfx}} <STDIN>}
  s/^>\K(?=(.*))/$h{$1}/;
' results.txt < filename.txt

関連情報