如何使用unix选择具有特定值的列

时间:2015-11-06 02:29:03

标签: unix text-files

我有以下示例制表符分隔文件:

.CvR    Col_1    Col_2    Col_3    Col_4    Col_5
S1    1    0    1    0    1
S2    1    1    1    0    1
S3    1    1    1    1    1
S4    1    0    1    1    1
S5    1    0    1    1    1

我试图想出一个简单的方法来打印第一列和所有列,只需" 1"其中的价值观。

我想要的输出文件应如下所示:

.CvR   Col_1    Col_3    Col_5
S1    1    1    1
S2    1    1    1
S3    1    1    1
S4    1    1    1
S5    1    1    1

我的实际输入文件会更大。我想尽可能在​​UNIX中这样做。有人可以帮忙吗?感谢。

3 个答案:

答案 0 :(得分:2)

你已经知道输入文件的行数,所以只需获取每个col的总和,并与最后一行索引减去1(col的总和)进行比较。

#!/bin/bash
# colSum is the last line index minus 1
cat input.txt | awk -v colSum=5 '{
    NR != 1
    for (i = 2; i <= NF; ++i) {
        sumOfCol[i] += $i
    } 
}
END {
    for (i in sumOfCol) {
        if (sumOfCol[i] == colSum)
            print i
    }
}'
执行此操作后,可以获得col的索引。也许这是一个简单的方法。

答案 1 :(得分:1)

你在找这个吗?

awk '{ print $1 " " $2 " " $4 " " $6 " "  }' file

.CvR Col_1 Col_3 Col_5 
S1 1 1 1 
S2 1 1 1 
S3 1 1 1 
S4 1 1 1 
S5 1 1 1 

答案 2 :(得分:1)

我认为最好的方法是在Excel中将文件作为csv文件读取,计算每列的总和并手动删除不需要的列。

使用sed成为一个肮脏而缓慢的解决方案。 sed解决方案的想法是将任何0或1值(@Lee:是的,我对你的帖子的评论对我有效,awk似乎是一个更好的解决方案)更改为具有列号和值的字段。
您可以计算找到值1的频率,并在未匹配总行数时删除该列。 变量值包含一个将与0或1匹配的表达式,并将存储在\ 1构造的内存中。

#!/bin/bash
clear
value='\([01]\)'
cp file file2
for i in 1 2 3 4 5 6; do
        sed -i "s/ ${value}/ val${i}_\1/"  file2
done
rowcount=$(wc -l <file2)
for i in 1 2 3 4 5 6; do
        if [ $(grep -c val${i}_1 file2) -eq ${rowcount} ]; then
                sed -i "s/val${i}_./1/"  file2
        else
                sed -i "s/Col_${i}//"  file2
                sed -i "s/val${i}_.//"  file2
        fi
done
cat file2