我想从标题(第一行)包含字符串“_HET”的文本文件中删除所有制表符分隔的列。输入文本文件如下所示:
rs36810213_HET rs2438689 rs70927523570_HET rs54666437 ...
1 0 2 0
0 1 0 1
2 0 1 1
... ... ... ...
输出文本文件应如下所示:
rs2438689 rs54666437 ...
0 0
1 1
0 1
... ...
我正在使用的代码不会删除任何内容:
#!/bin/bash
path="/data/folder"
awk -v OFS='\t' '
NR==1{
for (i=1;i<=NF;i++)
if ($i=="_HET") {
n=i-1
m=NF-(i==NF)
}
}
{
for(i=1;i<=NF;i+=1+(i==n))
printf "%s%s",$i,i==m?ORS:OFS
}
' $path/input.txt >> $path/output.txt
关于如何修复此代码有什么建议吗?谢谢你!
答案1
awk -F '\t' -f script.awk file
哪里script.awk
BEGIN { OFS = FS }
FNR == 1 {
for (i = 1; i <= NF; ++i)
if ($i !~ /_HET/)
keep[i] = 1
}
{
nf = split($0, fields, FS)
$0 = ""
j = 0
for (i = 1; i <= nf; ++i)
if (i in keep)
$(++j) = fields[i]
print
}
首先解析第一行的标头,并记住我们有兴趣将哪些标头保留在keep
关联数组中。
然后,对于每一行,它仅从我们想要保留的字段重新创建当前记录(行),并打印它。
它通过将当前字段分隔符上的行(重新)分割到数组中fields
,然后清空来实现此目的全部fields(带有$0 = ""
; 这将重置NF
),最后仅分配作为数组fields
中键的字段keep
。
有些人喜欢说俏皮话:
awk -F '\t' -v OFS='\t' 'FNR==1{for(i=1;i<=NF;++i)if($i!~/_HET/)k[i]=1}{n=split($0,f,FS);$0=j="";for(i=1;i<=n;++i)if(i in k)$(++j)=f[i]}1' file
我没有完全遵循您的代码,但$i=="_HET"
会将i
:th 字段与 string进行比较_HET
。除非该字段的值为确切地 _HET
(你的标题字段都不是)。
一种完全不同的方法:
cut -f "$( awk -F '\t' -v OFS="," '{for(i=1;i<=NF;++i)if($i!~/_HET/)k[i]=1;$0="";for(i in k)$(++j)=i;print;exit}' file )" file
这个使用awk
程序
BEGIN { OFS = "," }
{
for (i = 1; i <= NF; ++i)
if ($i !~ /_HET/)
keep[i] = 1
$0 = ""
for (i in keep)
$(++j) = i
print
exit
}
不输出内容所需列的数量,但将其列号输出为逗号分隔的字符串。然后使用该字符串cut
从数据中删除列。
答案2
您可以使用 Perl 执行此操作,如下所示:
$ perl -F'/\t/' -pale '$"="\t";
$. == 1 and @A = grep { $F[$_] !~ /_HET/ } 0 .. $#F;
$_ = "@F[@A]";
' input.tsv