因此,对于这个问题,我将给出两个示例代码块,两者之间略有不同。样本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解决此问题。
答案 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
}