![如何读取字符串输入文件,进行匹配并就地更改匹配?](https://linux22.com/image/197913/%E5%A6%82%E4%BD%95%E8%AF%BB%E5%8F%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BE%93%E5%85%A5%E6%96%87%E4%BB%B6%EF%BC%8C%E8%BF%9B%E8%A1%8C%E5%8C%B9%E9%85%8D%E5%B9%B6%E5%B0%B1%E5%9C%B0%E6%9B%B4%E6%94%B9%E5%8C%B9%E9%85%8D%EF%BC%9F.png)
我有一个文本文件,其中字符串/文件名位于单独的行中,例如。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.txt
但results.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()
替换前导>
,并作为变量>
传递(通过指令)。awk
prefix
-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;d
(1h
避免以换行符开始保留空间) 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