我有一个如下所示的数据文件
Sample1 Sample2 Sample3 Sample4 Sample5 Sample6
./. ./. ./. ./. ./. ./.
./. ./. ./. ./. A/G ./.
./. ./. ./. ./. ./. ./.
A/A A/A A/G ./. ./. ./.
我想删除仅包含 ./ 的所有列。留给我
Sample1 Sample2 Sample3 Sample5
./. ./. ./. ./.
./. ./. ./. A/G
./. ./. ./. ./.
A/A A/A A/G ./.
我觉得这是一个 sed 或 awk 命令,但感谢任何帮助。
答案1
使用awk
:
awk -v na="./." '
BEGIN{OFS=FS}
NR==FNR && NR>1 {
for(i=1;i<=NF;i++){if($i!=na){s[i]=1}}
}
NR!=FNR {
for(l in s){true}
for(i in s){if (i!=l){printf "%s"OFS,$i} else {printf "%s\n",$i}}
}
' file file
如果您的文件是制表符分隔的,您可能需要更改BEGIN{OFS=FS}
为。BEGIN{OFS=FS="\t"}
解释:
- 浏览文件两次(
awk ... file file
) - 第一次(
NR==FNR
为了NR>1
排除标题)您验证列 (i
) 中至少有一个值不是na="./."
,将列号保存在变量中s
。 - 第二次 ( ),对于保存在打印列值
NR!=FNR
中的每一列。s
(第一个循环让您知道要打印的最后一列(保存在变量中l
,因此您可以在打印OFS
或之间做出决定\n
。)
输出:
Sample1 Sample2 Sample3 Sample5
./. ./. ./. ./.
./. ./. ./. A/G
./. ./. ./. ./.
A/A A/A A/G ./.
如果您的文件是制表符分隔的,则输出会更好一点,如果不是,您可以添加|column -t
.然后它看起来像这样:
Sample1 Sample2 Sample3 Sample5
./. ./. ./. ./.
./. ./. ./. A/G
./. ./. ./. ./.
A/A A/A A/G ./.
答案2
$ perl -F'\t' -lane '
push @{$AoA[$.-1]}, map { push @Cols2Keep, $_ if $. > 1 && $F[$_] ne "./." && !$seen{$_}++; $F[$_] } 0 .. $#F}
{print join "\t", @{$AoA[$_]}[sort { $a <=> $b } @Cols2Keep] for 0 .. $#AoA
' file.tsv
结果:
Sample1 Sample2 Sample3 Sample5
./. ./. ./. ./.
./. ./. ./. A/G
./. ./. ./. ./.
A/A A/A A/G ./.
在职的:
- array of array @AoA,将文件存储在由记录号索引的数组中
$.
。因为$.
从 1 开始,而数组Perl
是0-indexed
我们标准化的$.
non ./.
数组 @Cols2keep 存储在其中找到元素的列号。我们也不希望其中有重复项,因此我们通过散列的方式对其进行重复数据删除,%seen
散列的键是这些列号。限制是我们跳过检查第一条记录。