如何提取其列名与 CSV 文件的特定模式匹配的整个列?

如何提取其列名与 CSV 文件的特定模式匹配的整个列?

我对 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最终包含01、 和2
  • @F[@wanted]语句中使用的 as实际上与(即 elements 、和of )print join()相同。这些元素用逗号字符连接并打印。@F[0,1,2]012@F

额外的东西:

if ($. == 1) {...}using 块可以foreach重写以使用 perl 的grep函数。整个块可以只用一行替换:

   @wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);

有人会说这更符合 Perl 习惯。我不同意 - perl 有foreachand grep(andmapjoin以及许多其他处理数组或列表的函数和运算符),并且使用任何其中有“惯用的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

使用非常简单磨坊主,谁的有一个正则表达式匹配列名的选项:

$ mlr --csv cut -r -f '^ABC' input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,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 开头的字段的字段编号。

接下来,有了这些信息,我们将其插入剪切命令中,以从整个文件中提取这些字段。

相关内容