使用AWK将FILENAME打印为CSV

时间:2016-03-14 19:59:35

标签: bash csv awk sed cat

我有一个小脚本来比较一堆CSV文件中的一些列。 它工作得很好,但有一些事情让我烦恼。

以下是代码:

FILES=./*
for f in $FILES

do
    cat -v $f | sed "s/\^A/,/g" > op_tmp.csv
    awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' op_tmp.csv >> output.csv
    rm op_tmp.csv
done

只是解释一下: 我得到目录上的所有文件,然后我使用CAT来替换管道的除数^ A。 然后我使用awk onliner比较我需要的列并将结果打印到output.csv。

但现在我想在每个循环之前打印文件名。 我尝试在同一行使用cat sed和awk并打印$ FILENAME,但它不起作用:

cat -v $f | sed "s/\^A/,/g" | awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' > output.csv

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

您可以更好地重写整个脚本,但假设它现在可以执行您想要的操作,只需添加

即可

def producer(): while True: if len(buff) == MAX_LEN: print("Producer: The buff is full, waiting...") sleep(10) buff.append(random.randint(1,9)) def consumer(): while True: print("Consumer: hi") if len(buff) == 0: print("Consumer: The buff is empty, waiting...") sleep(10) buff.pop()

在awk通话之前

如果要在每个awk输出行中添加文件名,则必须将其作为参数传递,即

echo $f >> output.csv

答案 1 :(得分:1)

重写:

for f in ./*; do
    awk -F '\x01' -v OFS="|" '
        BEGIN { 
            letter[1]="A"; letter[2]="C"; letter[3]="R"; letter[4]="P"; letter[5]="T" 
            letters["A"] = letters["C"] = letters["R"] = letters["P"] = letters["T"] = 1
        }
        NR == 1 {next} 
        $9 in letters {
            count[$9,$8] += $7
            seen[$8]
        }
        END { 
            print FILENAME
            for (i in seen) {
                sum = 0
                for (j=1; j<=4; j++) {
                    print i, letter[j], count[letter[j],i]
                    sum += count[letter[j],i]
                }
                print i, "T", count["T",i], (count["T",i] == sum ? "ERROR" : "MATCHED")
            } 
        }
    ' "$f"
done > output.csv

注意:

  • 如果您的文件名中包含空格,那么迭代文件的方法就会中断
  • 尝试尽可能减少重复。
  • 新行是免费的,使用它们来提高可读性
  • 改进您的变量名称in等 - 此处&#34;字母&#34;和#34;字母&#34;可以使用改进来保存关于这些符号的含义
  • awk有一个FILENAME变量(这里是您问题的实际答案
  • awk将\x01理解为Ctrl-A - 我认为这是输入文件中的字段分隔符
  • 定义您实际使用的输出字段分隔符

如果您有GNU awk(版本???),您可以使用ENDFILE块并完全取消shell for循环:

gawk -F '\x01' -v OFS="|" '
    BEGIN {...}
    FNR == 1 {next}
    $9 in letters {...}
    ENDFILE {
        print FILENAME
        for ...
        # clean up the counters for the next file
        delete count
        delete seen
    }
' ./* > output.csv