使用AWK如何删除所有包含特定标题的列

3

我有一个逗号分隔的csv文件,想要删除所有列中特定标题的内容,例如:

voltage, current, power, voltage, current, power
      2,       3,     6,      12,      12,   144  
      3,       5,    15,      10,      10,   100  

应该是

voltage, power, voltage, power  
      2,     6,      12,   144  
      3,    15,      10,   100  

你想要移除的标题是固定的“current”,还是可以是任何其他的? - Kent
4个回答

2

script.awk 内容如下:

BEGIN {
    FS=" , "
}

NR==1 {
    for (i=1; i<=NF; i++) {
        if ($i == "current") {
            array[i]++
        }
        else {
            printf (i != NF) ? $i", " : $i
        }
    }
}

NR>=2 {
    for (j=1; j<=NF; j++) {
        if (!(j in array)) {
            printf (j != NF) ? $j", " : $j
        }
    }
}

{
    printf "\n"
}

file.txt的内容:

voltage , current , power , voltage , current , power
2 , 3 , 6 , 12 , 12 , 144
3 , 5 , 15 , 10 , 10 , 100

运行方式:

awk -f script.awk file.txt

结果:

voltage, power, voltage, power
2, 6, 12, 144
3, 15, 10, 100

我不知道哪里出了问题,但这让我得到与输入文件相同的输出。 - FE RY
@FERY:你测试过我描述的输入文件了吗?你使用的是哪个版本的awk - Steve
@FERY:我应该说,你描述的输入文件中分隔符不一致。我假设你的输入是由 " , " 分隔的。如果需要,可以在 BEGIN 块中更改 FS 的值。 - Steve
2
@FERY:gawk是GNU AWK,可在Windows上使用,但来自Linux世界。我不会称其为“Windows上的AWK”。您应该知道CSV文件的概念非常模糊。您提供的示例数据在数据行中包括逗号周围的空格,但仅在标题行中的逗号之后。Steve在标题行的版本中在逗号之前添加了空格,然后按面值字面上将分隔符解释为空格-逗号-空格。这些都是重要细节。 - Dennis Williamson
@FERY:尝试将 if ($i == "current") 更改为 if ($i == "current" || $i == "voltage")。希望能有所帮助。 - Steve
显示剩余2条评论

1

如果您想删除所有标题为“current”的列:

kent$  awk -F',' 'NR==1{for(x=1;x<=NF;x++)if($x!="current")l[x]++;}{for(i=1;i<=NF;i++)if(i in l)printf (i==NF)?$i"":$i", ";printf "\n"}' test.txt 

voltage, power, voltage, power
2, 6, 12, 144
3, 15, 10, 100

注意:我已经删除了上面test.txt中的空格。

  • 如果您需要删除不同的标题,可以尝试使用正则表达式,并将$x!="foo"替换为正则表达式匹配。

  • 如果您知道要删除列的规则,例如第2列、第5列、第8列...(+3),那么可以通过循环更轻松地处理。


1
l(字母“l”)是一个不好的变量名选择,因为它很难与数字1(阿拉伯数字一)区分开来。此外,一些空格可以增强可读性。 - Dennis Williamson

0
请注意,对于一般的CSV文件处理,应使用适当的库。如果数据非常简单,即没有嵌入逗号、换行符等,则可以使用更简单的工具。
您从steve那里得到了一个很好的awk解决方案,因此我将添加一个基于coreutils和grep的答案:
# find columns to remove
pattern=current
cols=$(head -n1 a.csv | tr ',' '\n' | grep -n "$pattern" | cut -d: -f1 | paste -s -d,)

# remove all columns that matched
cut --complement -d, -f$cols a.csv

输出:

voltage, power, voltage, power
2 , 6 , 12 , 144
3 , 15 , 10 , 100

请注意,--complement 选项是 GNU cut 的扩展。要为其他切割生成 $cols ,可以尝试像这样的方法(已在 FreeBSD 上的 zsh 中测试):
# number of columns
file=a.csv
pattern=current
n=$(head -n1 "$file" | tr ',' '\n' | wc -l)

# generate complementary list
cols=$(jot $n \
| grep -xvFf <(head -n1 "$file" | tr ',' '\n' | grep -n "$pattern" | cut -d: -f1) \
| paste -s -d, -)

# remove columns
cut -d, -f$cols "$file"

我认为问题的重点在于有许多列需要删除,它们的位置不一定固定或在固定间隔上。 - Dennis Williamson
改为 coreutils 解决方案。 - Thor

0
假设输入文件名为input.txt。
awk  -F ',' '{print $1 "," $3 "," $5 "," $6 }' input.txt

问题在于列数太多了(2500),所以我需要一个循环来遍历所有的列。 - FE RY

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接