我对 Unix 不太熟悉,现在正在处理一个非常大的 CSV 文件。
这是一个例子:
ABC1,ABC2,ABC3,DDD,EEE,FFF
1,2,3,4,5,6
1,2,3,4,5,6
如何提取以 开头的所有列ABC
?
答案1
下面的awk
程序就可以了。将其存储在文件中,例如extract.awk
:
#!/bin/awk -f
BEGIN { FS=OFS=","}
FNR==1 {
for (i=1;i<=NF;i++) {
if (index($i,startstr)==1) cols[++ncol]=i;
}
}
{ for (j=1;j<=ncol;j++) printf("%s%s",$(cols[j]),j==ncol?ORS:OFS) }
然后你可以将其称为
~$ awk -f extract.awk -v startstr="ABC" input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
您在变量中定义要查找的字符串的位置startstr
。
这将首先将输入和输出字段分隔符设置为,
。
- 在第一行(标题行)中,它将检查是否有任何列名称以搜索字符串开头,该搜索字符串存储在变量 中
startstr
。如果是这样,列号将被添加到cols
“要打印的列”数组中。 - 对于每一行(包括第一行),它将打印存储在中的所有列的值
cols
,然后打印字段分隔符或记录分隔符(默认为换行符)(如果它是最后一列)。
请注意,我们使用 的index()
函数进行文字字符串匹配,而不是基于正则表达式的awk
匹配,以防您的实际搜索字符串包含正则表达式上下文中的特殊字符。如果必须使用正则表达式基本搜索,请更改
if (index($i,startstr)==1) cols[++ncol]=i;
到
if ($i ~ startstr) cols[++ncol]=i
但请注意,其中的所有字符startstr
都会被解释为正则表达式标记,如果不小心,可能会导致意外的行为。对于您提到的示例,startstr
将是^ABC
.
答案2
您可以使用 awk 来完成此操作,但由于 Perl 的数组切片功能,因此在 Perl 中更容易。在 awk 中,您必须迭代所需的数组才能获得相同的结果。
#!/usr/bin/perl
use strict;
my @wanted; # array to hold the indices we want to print
while(<>) {
chomp;
# split the input line into array @F, using commas as the delimiter.
my @F = split /,/;
if ($. == 1) { # process the first line (the headers)
# if a header matches the regex, add it to @wanted
foreach my $i (0 .. $#F) {
push @wanted, $i if $F[$i] =~ m/^abc/i;
};
};
# print the columns of @F whose indices are listed in @wanted
print join(",", @F[@wanted]), "\n";
}
另存为,例如,abc.pl
并使用 使其可执行chmod +x abc.pl
,然后像这样运行:
$ ./abc.pl input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
这是如何运作的:
- 循环
foreach
将每个字段匹配的索引号/abc/
(不区分大小写)添加到@wanted
数组中 - 给定样本输入后,
@wanted
最终包含0
、1
、 和2
。 @F[@wanted]
语句中使用的 as实际上与(即 elements 、和of )print join()
相同。这些元素用逗号字符连接并打印。@F[0,1,2]
0
1
2
@F
额外的东西:
if ($. == 1) {...}
using 块可以foreach
重写以使用 perl 的grep
函数。整个块可以只用一行替换:
@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
有人会说这更符合 Perl 习惯。我不同意 - perl 有foreach
and grep
(andmap
和join
以及许多其他处理数组或列表的函数和运算符),并且使用任何其中有“惯用的perl”。
注意:keys
在索引数组上使用需要高于或等于 v5.12 的 perl 版本,该版本于 2010 年发布。在此之前,keys
仅适用于哈希数组。
此外,整个脚本可以压缩为一行,只有两条语句:
$ perl -F, -lne '@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
print join(",", @F[@wanted]);' input.csv
答案3
答案4
flds=$(< file head -n 1 | tr ',' '\n' | grep -ne '^ABC' | cut -d: -f1 | paste -sd, -)
cut -d, -f"${flds}" file
ABC1,ABC2,ABC3
1,2,3
1,2,3
我们分两步进行,首先提取标头,然后从中获取以 ABC 开头的字段的字段编号。
接下来,有了这些信息,我们将其插入剪切命令中,以从整个文件中提取这些字段。