我正在考虑使用 bash 代码来解决我的数据中的以下问题。
考虑到 hapmap 格式的以下数据集,我需要根据“等位基因”列的数据替换一些字符(在本例中为字母)。 “等位基因”列中的数据将是四个字母对的组合(A、G、C 和 T)。
rs# alleles chro pos ind1 ind2 ind3 ind4 ind5 ind6. .
mar_1 G/T 1 2386806 G T T G K T
mar_2 T/G 1 2386848 T G T K T K
mar_3 G/T 1 2387553 T K G K T G
mar_4 G/A 1 2564608 G G G N R A
mar_5 C/T 1 2564616 C Y C Y T N
.
.
我想要得到的是一个遍历整行的代码(在第 1 行的情况下),当它找到字母“T”(“/”之后的字母)时,将其替换为字母“G”(之前的字母)当它找到字母“R”、“Y”、“S”、“W”、“K”或“M”时,将其替换为“T”(“/”之后的字母)。
换句话说,代码必须(在每一行中)找到与“/”之后的字母(在“等位基因”列中)匹配的所有字母,并将它们替换为与“/”之前的字母匹配的字母。并且,当它找到与以下之一匹配的字母时:(“R”、“Y”、“S”、“W”、“K”或“M”),它必须将其替换为匹配的字母与“/”后面的一个。
我想得到的输出是:
rs# alleles chro pos ind1 ind2 ind3 ind4 ind5 ind6. .
mar_1 G/T 1 2386806 G G G G T G
mar_2 T/G 1 2386848 T T T G T G
mar_3 G/T 1 2387553 G T G T G G
mar_4 G/A 1 2564608 G G G N A G
mar_5 C/T 1 2564616 C T C T C N
.
.
注意:“N”表示缺失值,因此必须保留原样。
任何有关此问题的帮助将不胜感激。
答案1
和perl
$ perl -F'\s+|/' -lape '
s/^(\S+\s+){4}\K.*/$&=~s|$F[2]|$F[1]|gr/e;
s/^(\S+\s+){4}\K.*/$&=~s|[RYSWKM]|$F[2]|gr/e
' ip.txt
rs# alleles chro pos ind1 ind2 ind3 ind4 ind5 ind6. .
mar_1 G/T 1 2386806 G G G G T G
mar_2 T/G 1 2386848 T T T G T G
mar_3 G/T 1 2387553 G T G T G G
mar_4 G/A 1 2564608 G G G N A G
mar_5 C/T 1 2564616 C T C T C N
-F'\s+|/'
按空格或/
字符分割输入行,保存在@F
数组中^(\S+\s+){4}\K.*
将获取除前四列之外的所有列$&=~s|$F[2]|$F[1]
在匹配部分(前四列除外)执行另一次替换$F[2]
将包含之后的字符/
并且$F[1]
将包含之前的字符/
- 修饰符
r
返回最终替换的字符串,并且e
修饰符允许在替换部分使用 Perl 代码 - 由于再次使用相同的模式,第二次替换也可以缩短为
s//$&=~s|[RYSWKM]|$F[2]|gr/e
- 看命令开关
-lape
有关选项的解释
答案2
perl -F'/(\s+|\/)/' -lne '
print @F[0..9], map { s/($F[4])|([RYSWKM])/$2?$F[4]:$F[2]/re } @F[10..$#F];
' hapmap.txt
sed -e '
s/^\(\S\+\s\+\)\{4\}/&\n/ # mark col-4
:a
s|^\(\S\+\s\+\(.\)/\(.\).*\n.*\)\3|\1\2|g;ta # perform sub-1
:b
s|^\(\S\+\s\+\(.\)/\(.\).*\n.*\)[RYSWKM]|\1\3|g;tb # perform sub-2
s/\n//g # throw away marker
' hap_map.txt