如何讀取字串輸入文件,進行匹配並就地更改匹配?

如何讀取字串輸入文件,進行匹配並就地更改匹配?

我有一個文字文件,其中字串/文件名位於單獨的行中,例如。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與行號一起使用來更改單行或行塊。

我想要的輸出看起來像

>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

相關內容