对AWK如何处理命令感到困惑

时间:2020-10-21 23:12:41

标签: bash csv awk

因此,对于这个问题,我将给出两个示例代码块,两者之间略有不同。样本1给出正确的结果,样本2给出不正确的结果。 此处正确的结果意味着它应该能够读取应该从csv文件读取的字段,并仅打印这些字段中存在的字符串的计数。示例代码后显示以下示例。 请注意,该程序是用来跳过CSV文件中的标题行的。

示例1:

#!/bin/awk -f

BEGIN {
    FIELDS_LIST = ARGV[1];
    delete ARGV[1];
    FS = ", *"

    num = split(FIELDS_LIST,arr,",")
    for(i in arr)
        fields[arr[i]]
}

{
    for(i = 1; i <= NF; i++)
    {
        if(FNR != 1)
          if(i in fields)
            data[++data_index] = $i
    }

}

END {
    produce_numbers(data)

    PROCINFO["sorted_in"] = "@val_num_desc"

    for(i in freq)
        printf "%s\t%d\n", i, freq[i]
}

function produce_numbers(sortedarray)
{
    n = asort(sortedarray)

    for(i = 1 ; i <= n; i++)
    {
        freq[sortedarray[i]]++
    }
    return
}

示例2:

#!/bin/awk -f

BEGIN {
    FIELDS_LIST = ARGV[1];
    delete ARGV[1];
    FS = ", *"

    num = split(FIELDS_LIST,arr,",")
    for(i in arr)
        fields[arr[i]]
}

{
    for(i = 1; i <= NF; i++)
    {
        if(FNR != 1)
          if(i in arr)                 #This is the only line changed, fields was changed to arr
            data[++data_index] = $i
    }

}

END {
    produce_numbers(data)

    PROCINFO["sorted_in"] = "@val_num_desc"

    for(i in freq)
        printf "%s\t%d\n", i, freq[i]
}

function produce_numbers(sortedarray)
{
    n = asort(sortedarray)

    for(i = 1 ; i <= n; i++)
    {
        freq[sortedarray[i]]++
    }
    return
}

将使用类似./example-awk.awk 2,3 simple.csv且包含simple.csv的代码来调用代码

Field1,Field2,Field3,Field4
A,V,A,C
B,C,V,D
E,W,C,A

结果应该是

V    2
C    2
A    1
W    1

样本1提供了正确的结果,样本2提供了

A    1
B    1
C    1
E    1
W    1
V    1

表明它仅从字段1和2读取,而不是从命令行参数指定的2和3读取。 我想知道为什么在begin中创建第二个数组,然后使用它代替原始的arr解决此问题。

1 个答案:

答案 0 :(得分:3)

if (i in arr)

测试i是否为arr数组中的键。但是您想要的字段编号是数组中的值,而不是索引。

您可以遍历arr而不是循环遍历所有字段并对其进行测试。

此外,您应该在执行该行的任何代码之前测试FNR != 1,以跳过标头,而不是每次都循环。

#!/bin/awk -f

BEGIN {
    FIELDS_LIST = ARGV[1];
    delete ARGV[1];
    FS = ", *"

    num = split(FIELDS_LIST,arr,",")
    for(i in arr)
        fields[arr[i]]
}

FNR != 1 {
    for (i in fields)
        data[++data_index] = $i
}

END {
    produce_numbers(data)

    PROCINFO["sorted_in"] = "@val_num_desc"

    for(i in freq)
        printf "%s\t%d\n", i, freq[i]
}

function produce_numbers(sortedarray)
{
    n = asort(sortedarray)

    for(i = 1 ; i <= n; i++)
    {
        freq[sortedarray[i]]++
    }
    return
}