如何读取字符串输入文件,进行匹配并就地更改匹配?

如何读取字符串输入文件,进行匹配并就地更改匹配?

我有一个文本文件,其中字符串/文件名位于单独的行中,例如。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

相关内容