【问题标题】:AWK file conversionAWK 文件转换
【发布时间】:2018-09-05 22:08:14
【问题描述】:

我有一个格式如下的文件:

Total:89.3    
User: user1
    Count:3
    Sum:80
      departmentId: dept1
      Amount by departmentId: 20
      departmentId: dept1
      Amount by departmentId: 35
      departmentId: dept2
      Amount by departmentId: 25
    User: user2
    Count:3
    Sum:7.199999999999999
      departmentId: dept1
      Amount by departmentId: 2.4
      departmentId: dept2
      Amount by departmentId: 2.4
      departmentId: dept3
      Amount by departmentId: 2.4
    User: user3
    Count:1
    Sum:0.2
      departmentId: dept2
      Amount by departmentId: 0.2
    User: user4
    Count:2
    Sum:2
      departmentId: dept3
      Amount by departmentId: 1
      departmentId: dept3
      Amount by departmentId: 1

文件列表基本上是一个部门的用户会费。如果同一用户多次归于一个部门,则需要将其合并到一行中。输出文件需要采用以下格式。 对于用户 1,他有 2 个部门的应付款和 1 个部门的应付款。因此,在输出文件中,需要将 dept1 的 2 个会费合并为 1 个计数需要为 no。每个部门的唯一用户数。

Format:
count_of_uique_user_dept_rows total_sum   -- note** header row-->total sum and total no. of unique user dues
userId+deptId sum for that dept

Example:

7 89.3
user1dept1 55
user1dept2 25
user2dept1 2.4
user2dept2 2.4
user2dept3 2.4
user3dept2 0.2
user4dept3 2

目前为止,

# This awk script is used to convert the input of library credit/debit's to the required Student Accounts Load format
BEGIN { FS=": *" }
{
    gsub(/^ +| +$/,"")
    f[$1] = $2

}
/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    amount += $2

}
$1 == "User" {
    if (NR>1) {
        format()
    }
    user = $2
}
END { format() }

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        printf "%-9s%-12s%10.2f\n", substr(user,1,9), substr(dept,1,12), sum[dept]
    }
    delete sum
    amount = 0
 }
}

上面的脚本给了我们数据行。我无法弄清楚如何获得 7 89.3 的标题行请帮助。

【问题讨论】:

  • usrdpt[user,dept] 每当看到 dept 时。在末尾打印length(usrdpt)
  • 我可以在哪里打印?因为这只需要打印一次,在标题上
  • 是的,我只是在增强现有功能。 awk 新手,试图理解它。
  • 从一个文件中读取,所以我们可以读取两次。会试一试。谢谢

标签: shell awk scripting


【解决方案1】:

我决定不读取文件两次,而只是在打印前将输出保存在一个数组中。这样做的方法如下:

第 1 步:通过在其中添加 delete sum 数组操作,修复由于您在将 length(sum) 用作数组之前调用 length(sum) 而导致某些 awks 假设 sum 是标量时您会从其中得到的语法错误BEGIN 部​​分(您可以删除对 length(sum) 的测试,因为它在您的代码中没有做任何有用的事情,但我想解释这个问题以及如何解决它)。

BEGIN { FS=": *"; delete sum }

第 2 步:更改 format() 函数以加载稍后输出的值数组,而不是立即输出这些值:

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        vals[++numVals] = sprintf("%-9s%-12s%10.2f", substr(user,1,9), substr(dept,1,12), sum[dept])
    }
    delete sum
    amount = 0
 }

}

第 3 步:在 END 部分添加一个循环来实际执行打印:

END {
    format()
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

此时,您获得的输出将与您现有的脚本完全相同,但它使我们能够添加您需要的新功能:

第4步:将每个用户+部门组合保存为数组usrdpt[]的索引:

/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    usrdpt[user,dept]
    amount += $2
}

第 5 步:在打印之前的值之前,在 END 部分打印新的 usrdpt[] 数组的唯一索引数:

END {
    format()
    print length(usrdpt)
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

结果是:

$ cat tst.awk
BEGIN { FS=": *"; delete sum }
{
    gsub(/^ +| +$/,"")
    f[$1] = $2
}
/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    usrdpt[user,dept]
    amount += $2
}
$1 == "User" {
    if (NR>1) {
        format()
    }
    user = $2
}
END {
    format()
    print length(usrdpt)
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        vals[++numVals] = sprintf("%-9s%-12s%10.2f", substr(user,1,9), substr(dept,1,12), sum[dept])
    }
    delete sum
    amount = 0
 }
}

.

$ awk -f tst.awk file
7
user1    dept1            55.00
user1    dept2            25.00
user2    dept1             2.40
user2    dept2             2.40
user2    dept3             2.40
user3    dept2             0.20
user4    dept3             2.00

我假设您可以弄清楚如何保存并稍后打印 Total 值。

【讨论】:

  • 非常有效的方法,不用两次读取文件。效果很好。非常感谢
【解决方案2】:

使用 GNU awk 和二维数组:

$ awk '
$1=="User:" {                                 # store user
    u=$NF 
}
$1=="departmentId:" {                         # store dept
    d=$NF
}
$1=="Amount" {
    if(a[u][d]=="")                           # count uniq user/depts
        c++
    s+=$NF                                    # total sum
    a[u][d]+=$NF                              # user/dept sum
}
END {
    printf "%s, %.2f\n",c,s                   # output count and total
    for(u in a)
        for(d in a[u]) 
            printf "%s %s %.2f\n",u,d,a[u][d] # output user/dept sums
}' file

输出:

7 89.40
user1 dept1 55.00
user1 dept2 25.00
user2 dept1 2.40
user2 dept2 2.40
user2 dept3 2.40
user3 dept2 0.20
user4 dept3 2.00

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多