我有一个包含许多列的文件,我试图挑选出它们的一部分。该子集不是由连续范围定义的(例如,我不能迭代2到10)。
示例:
$ cat test
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
$ cat index
3
5
9
此示例中的预期输出:
3 5 9
6 10 18
我想要第3,第5和第9列(比如说)。
我知道我可以awk '{print $3, $5, $9}' test
在这里做{但是这在我的真实数据中是不可行的> 100列,我需要选择>其中50个。因此,请不要建议手动编写所有列号。
我目前的一个非常糟糕的解决方案如下:
while read column
do
awk -v var=$column '{print $var}' test > "$column"
done < index
将与我想要的列(保存在名为index
的文件中)对应的各列放入单个文件(根据索引命名),然后将它们粘贴在一起。
这感觉非常低效,我确信有更好的方法。 你能建议吗?
答案 0 :(得分:2)
$ cut -d ' ' -f $(paste -s -d ',' index) infile
3 5 9
6 10 18
cut
在-f
选项中以逗号分隔的字段列表,paste -s -d ','
从index
文件创建该列表。
您的输入是制表符分隔的,您可以从-d ' '
命令中删除cut
。
答案 1 :(得分:2)
由于此问题已被标记为:[bash awk],因此我会使用两者来解决问题:
printf -v var "$%s, " $(<index)
awk "{print ${var%, }}" test
3 5 9
6 10 18
通过使用双引号("
),我确保awk不会看到$var
,只会看到它的内容。
答案 2 :(得分:1)
与其他好的答案相比,我似乎很冗长 但我可以把它留在这里作为一些复杂/复杂案例(分隔规则或字段过滤)的替代方案:
假设test
文件包含:
1 2 3 4 5 6 7 8 9 10 15 25 30 35 45 75 80 90
2 4 6 8 10 12 14 16 18 20 40 50 60 70 85 100
我们需要提取文件index
中指定位置的所有字段,内容为:
3
5
9
8
12
14
工作:
indices=$(<index)
echo $indices | awk -v f="$indices" 'BEGIN{split(f, a, "\n")}
{f=""; for (i=1;i in a;i++) {printf "%s%s", f, $a[i]; f=OFS} print ""}' test
您可以在split(f, a, "\n")
函数调用
输出:
3 5 9 8 25 35
6 10 18 16 50 70
答案 3 :(得分:0)
仅限Awk:
$ awk '
NR==FNR { a[$1]; next } # code for index file
{ # code for test file below this point
for(i=1;i<=NF;i++)
printf "%s%s", (i in a ? $i OFS : ""), (i==NF ? ORS : "")
}' index test
3 5 9
6 10 18
解决方案读入index
文件,并将要打印的字段编号存储到a
哈希。然后test
的所有字段都会for
进行迭代,而i
中的a
字段printf
将以ORS
结束{/ 1}}。
答案 4 :(得分:0)
由于我得到了很多答案,我认为我会对它们进行基准测试。 我生成了一个包含1000列和10,000行的文件。为了生成索引,我随机选择了一个包含100个数字的子集。
@Benjamin W -
time cut -d ' ' -f $(paste -s -d ',' index) test | wc -l
10000
real 0m0.844s
user 0m0.839s
sys 0m0.020s
@F。 Hauri
printf -v var "$%s, " $(<index) ; time awk "{print ${var%, }}" test
10000
real 0m0.242s
user 0m0.233s
sys 0m0.017s
@RomanPerekhrest
indices=$(<index)
time echo $indices | awk -v f="$indices" 'BEGIN{split(f, a, "\n")}
{f=""; for (i=1;i in a;i++) {printf "%s%s", f, $a[i]; f=OFS} print ""}' test
10000
real 0m0.460s
user 0m0.456s
sys 0m0.016s
@James Brown
time awk '
NR==FNR { a[$1]; next }
{
for(i=1;i<=NF;i++)
printf "%s%s", (i in a ? $i OFS : ""), (i==NF ? ORS : "")
}' index test | wc -l
10000
real 0m2.667s
user 0m2.658s
sys 0m0.018s