awk重新分析没有getline的管道输入

时间:2014-06-23 15:19:28

标签: bash awk gawk

我写了一个awk脚本,它将解析管道输入并将其转换为间隔很大的表。 为此,我需要解析输入流两次。首先解析每列的实际列大小。然后打印表本身。

#!/bin/gawk -f
# with changes from ooga

BEGIN {
    FS=" "
    buffer = "mktemp" | getline result
    # Initialize Vars
}

{
    # Count Columns...
}

END{
    close(buffer)

    while((getline < buffer) > 0){
        # Print formated table
    }
}

所以这项工作正常,但它使用getline并且所有手册都指出,很少有真正需要getline的情况。我认为唯一的其他选择是使用文件而不是管道。

gawk中有另一个选项可以解析管道输入两次吗?

2 个答案:

答案 0 :(得分:2)

只需将输入存储在数组中然后打印即可。你没有发布任何样本输入和预期输出,所以没有什么我们可以测试,但这样的东西可能是你想要的:

awk '
{
    line[NR] = $0
    curLength = length($0)
    if (curLength > maxLength)
        maxLength = curLength
}
END {
    for (i=1; i<=NR; i++) {
        printf "| %*s |\n", maxLength, line[i]
    }
}
'

答案 1 :(得分:1)

这并不是一个更好的方法(编辑:实际上,正如Ed Morton所说,使用数组可能更好;看看他的帖子和我在这个结尾的替代例子但是,这不是一个非常糟糕的问题。程序,因为它没有使用pattern{action}范例。 awk对此程序的唯一优势是自动字段拆分。

一些提示:

  • FS默认为单个空格(具有特殊含义,即字段由空格的运行分隔,并且忽略前导和尾随空格。)因此无需明确将它设置为空格。

  • |&打开一个协同进程,但您只需要一个常规管道,所以只需|

  • 您应该明确关闭管道。

  • 这个功能似乎是一个不必要的并发症。

  • 您应该在完成后删除临时文件。

这会产生:

#!/bin/gawk -f

BEGIN {
    "mktemp" | getline tmpfile
    close("mktemp")
}

{
    # process and save piped data to tmpfile
}

END {
    close(tmpfile)
    while((getline < tmpfile) > 0) {
        # process data from tmpfile
    }
    system("rm " tmpfile)
}

以下是使用数组而不是临时文件的示例:

#!/bin/awk -f

{
    line[NR] = $0
    if (NF > nf)
        nf = NF;
    for (i=1; i<=NF; ++i)
        if (length($i) > flen[i])
            flen[i] = length($i)
}

END {
    for (r=1; r<=NR; ++r) {
        for (f=1; f<=nf; ++f) {
            split(line[r], fields)
            printf("| %-*s ", flen[f], fields[f])
        }
        print "|"
    }
}

输出:

$ cat file
one two three
four five six
seven eight nine
$ cat file | ./columnize.awk
| one   | two   | three |
| four  | five  | six   |
| seven | eight | nine  |
$