![如何根据输入列表批量更改文件中的文本](https://linux22.com/image/110821/%E5%A6%82%E4%BD%95%E6%A0%B9%E6%8D%AE%E8%BE%93%E5%85%A5%E5%88%97%E8%A1%A8%E6%89%B9%E9%87%8F%E6%9B%B4%E6%94%B9%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E6%96%87%E6%9C%AC.png)
我有大量数据,如下所示
文件1(4600行)
Genome Gene Boolean
E15-12 VFG000923 1
E15-13 VFG000924 1
E15-14 VFG000926 1
E15-15 VFG000928 1
E15-16 VFG000930 1
E15-17 VFG000932 1
E15-18 VFG000933 0
E15-19 VFG001448 0
E15-24 VFG013465 1
我想将 col2 中的信息细分为:
文件2(180行)
VFG000923|fepA
VFG000924|fepB
VFG000926|fepD
VFG000928|fepG
VFG000930|entF
VFG000932|entE
VFG000933|entB
VFG001448|kpsD
VFG001450|kpsM
VFG044165|entS
出去
Genome Gene Boolean
E15-12 VFG000923|fepA 1
E15-13 VFG000924|fepB 1
E15-14 VFG000926|fepD 1
E15-15 VFG000928|fepG 1
E15-16 VFG000930|entF 1
E15-17 VFG000932|entE 1
E15-18 VFG000933|entB 0
E15-19 VFG001448|kpsD 0
E15-20 VFG001450|kpsM 1
使用@val0x00ff的代码(见评论)
Genome Gene Boolean
E15-14 VFG000923|fepA 1
E15-14 VFG000924|fepB 0
E15-14 VFG000926|fepD 1
E15-14 VFG000928|fepG 0
有没有办法用 sed 或 awk 来做到这一点?
答案1
和sed
:
sed '/|/{H;d;};G;s/\([A-Z0-9]*\)\(.*\n\)\1\(|[^[:cntrl:]]*\)/\1\3\2\1\3/;P;d' FILE2 FILE1
应该可以解决问题。这是一个改编这个答案。详细的解释在那里。
答案2
这应该有效:
$ awk 'NR==FNR{k=sub(/\|.*/,$1); a[k]=$1; next} ($2 in a){$2=a[$2]}1' file2 file
Genome Gene Boolean
E15_14 VFG000923|fepA 1
E15_14 VFG000924|fepB 1
E15_14 VFG000926|fepD 0
E15_14 VFG000928|fepG 1
E15_14 VFG000930|entF 0
E15_14 VFG000932|entE 0
E15_14 VFG000933|entB 1
E15_14 VFG001448|kpsD 1
E15_14 VFG001450|kpsM 1
E15_14 VFG044165|entS 0
或者,更容易阅读:
awk 'NR==FNR{
k=sub(/\|.*/,$1);
a[k]=$1;
next
}
($2 in a){
$2=a[$2]
}1' file2 file
解释
NR==FNR{ }
:NR 为当前输入行号,FNR 为当前文件的行号。当读取多个文件时,仅在读取第一个文件时两者才相等。k=sub(/\|.*/,$1);
:从该行中删除后面的部分|
(由于如上所述,这只发生在第一个文件中NR==FNR
)。a[k]=$1;
:将第一个文件的第一个字段保存为数组中的值,a
其键为基因名称(第一个字段|
删除后的所有内容)。next
: 跳到下一行。这确保我们在读取第一个文件时不会执行下一个块。($2 in a)
:如果第二个字段作为数组中的键存在a
(这只会针对第二个文件运行)。$2=a[$2]
:将第二个字段设置为存储在a
for中的任何内容$2
。1
:这是 awk 的“打印当前行”的简写。它之所以有效,是因为当 awk 中某项计算结果为 true 时,默认操作是打印当前行。由于1
始终为真,因此将打印出来。
答案3
perl -lne '
@ARGV and %h=(%h, /(.*)\|/ => $_),next;
!@ARGV and !$a++ and print,next;
print s//$h{$1}/r if exists $h{(/\h\K(\S+)(?=\h)/)[0]};
' FILE2 FILE1
解释
- 当读入较小的文件(FILE2)时,我们填充之前数据的
%h
哈希值,值是整行。keyed
|
- 当读取较大的文件(FILE1)时,我们首先使用以下命令打印它的第一行:
!@ARGV and !$a++
含义已被清空,并且我们第一次@ARGV
看到该变量。$a
- 在剩下的行中,我们查看是否通过 标识的第二个字段
regex
/\h\S+\h/
来查看该键是否存在于哈希中%h
。当发现这是真的时,我们将该字段替换为与该键对应的值。