【问题标题】:Why does my AWK-Script wait for me to press a key?为什么我的 AWK 脚本等待我按下一个键?
【发布时间】:2019-07-09 09:39:28
【问题描述】:

我今天开始学习 AWK,我编写了一个计算 2 次方的脚本。但是,当我启动它时,它会等待我按 Enter 键,当它打印完 2 的幂时,它不会打印“End”这个词,尽管它是在 End 部分中定义的。

这是我的代码:

BEGIN{
    print "Power of two"
    x=0
}
{
while(res<=1000){
    res = 2^x
    print 2 "^" x "=" res
    x++
}
}
END{
    print "End"
}

【问题讨论】:

  • 因为我相信您没有将任何 Input_file 传递给awk 程序?
  • 我通过输入“gawk -f poweroftwo.awk”打开脚本
  • 好的,我刚刚正确地看到了您的脚本,您并没有尝试对输入数据进行操作,而是想要一个独立的 awk 脚本。将整个代码放入 BEGINEND 或两者中,但你不能有介于两者之间的东西..这会告诉 awk 寻找输入数据..另外,我认为 gawk 版本 5+ 不允许这种使用
  • @Sundeep - 她应该把它放在 BEGIN,而不是 END(脚本只会挂起)。知道I think gawk version 5+ will not allow this kind of use 是什么意思,但如果是这样的话,gawk 将不允许只包含 BEGIN 的脚本 - 是的,它会。
  • @Sundeep 是的,-e 功能让您可以将最近更改的命令行 (-e) 和基于文件的 (-f) 脚本交错。现在我记得了——每个 sn-p 必须在语法上独立独立,所以你仍然可以写 -e 'BEGIN{print "foo"}' -e 'END{print "bar"}',但你不能再写 -e 'BEGIN{print "foo"' -e '} END{print "bar"}'。他们必须做出改变来实施namespaces

标签: awk


【解决方案1】:

您通过在 BEGIN 和 END ({while ... }}) 之间提供代码来处理输入来告诉脚本期待输入。该部分在您通过按 Enter 提供输入之前不会开始,然后在您通过键入 control-D 结束输入之前它不会结束,此时您的 END 部分将被执行。

这听起来像是你打算写的:

BEGIN{
    print "Power of two"
    x=0

    while(res<=1000){
        res = 2^x
        print 2 "^" x "=" res
        x++
    }

    print "End"
}

或者如果您出于某种原因真的想要一个 END 部分:

BEGIN{
    print "Power of two"
    x=0

    while(res<=1000){
        res = 2^x
        print 2 "^" x "=" res
        x++
    }

    exit
}
END{
    print "End"
}

【讨论】:

  • 看起来不错,非常透彻,我已经对前一个版本投了赞成票,否则我现在会再做一次。
【解决方案2】:

awk 在中间部分需要一些输入(正如@Sundeep 所写)

试试这个

echo "50" | awk '
BEGIN{
    print "Power of two"
    x=0
}
{
while(res<=$1){
    res = 2^x
    print 2 "^" x "=" res
    x++
}
}
END{
    print "End"
}'
Power of two
2^0=1
2^1=2
2^2=4
2^3=8
2^4=16
2^5=32
2^6=64
End

【讨论】:

  • 对不起,迟到的评论,只是想澄清一下:所以,如果在 AWK 程序中存在中间部分,即BEGIN{}END{} 之间的部分,那么它总是需要一些输入(用户、管道或其他),对吗?如果我不想提供这样的输入,那么我只能将我的代码放在BEGIN{}END{} 部分,对吗?
  • @AS 据我所见,是的。中间块需要某种形式的输入。 BEGIN 和 END 块在处理输入代码之前和之后处理。
【解决方案3】:

您的程序在按键时执行进一步操作的原因是它正在等待输入。使用管道时,输入通常来自文件或来自另一个命令的输出。但是,awk 有时会等待来自/dev/stdin 的输入。当您在没有任何文件作为参数的情况下调用程序时就是这种情况(参见[1] 部分扩展描述:整体程序结构),或使用 作为参数(参见[1] 部分操作数)。

$ awk -f source.awk                 # input from /dev/stdin via keyboard 
$ awk -f source.awk [file] -        # input from /dev/stdin via [file and] keyboard
$ cmd | awk -f source.awk           # input from /dev/stdin via pipe
$ cmd | awk -f source.awk [file] -  # input from /dev/stdin via [file and] pipe

请注意,上述情况可能需要来自/dev/stdin 的输入。是否需要输入取决于 awk 的程序结构。所以我们现在可以问自己以下问题:

awk 何时需要来自文件、命令、键盘或任何其他可能的输入形式的输入?

一个 awk 程序由以下形式的对组成:

pattern { action }

其中pattern 通常是确定是否应执行action 的逻辑条件。 Posix awk 识别两种特殊模式,BEGINEND。 Gnu awk 还有其他特殊模式,例如BEGINFILEENDFILE,但是对于这个答案,我们可以将它们归类为常规模式。我们现在可以做出以下陈述(参见[1] 小节特殊模式):

  • 常规模式总是需要输入。
  • 特殊模式BEGIN不需要输入(除非它包含getline
  • 特殊模式END总是要求在执行前读取输入

由此我们可以说:

一个 awk 程序不需要输入如果

  • 它只包含BEGIN 不调用getline 的模式。
  • 或者,BEGIN 模式在调用任何getline 之前调用exit 例程

在任何其他情况下,awk 都需要输入!

最后一条语句来自绑定到exit 语句的规则。 exit 语句应按照它们在程序源中出现的顺序调用所有END 动作,然后终止程序而不读取进一步的输入。 (参见[1] 小节操作

基于以上,我们现在可以回答OP的问题了:

为什么我的 AWK 脚本要等我按键?

由于OP的程序大致如下:

 BEGIN { something without exit }
 pattern { something else }
 END { something final }

它需要输入。此外,OP将其称为

$ awk -f file.awk

这意味着输入来自/dev/stdin,或者在本例中为键盘。因此 awk 将等待执行常规的动作模式对,直到它从键盘接收到一条记录(这里是一行)。 IE。按一些键,然后按 Enter。每次发送这样的一行时,awk 都会处理所有常规模式。 END 模式只会在输入完成时执行。您可以通过键盘发送文件结尾 (EOF) 来通知 awk 通过键盘输入已完成。这是通过按 Ctrl-D 来完成的。

代码的干净重写可以在Ed Morton 的答案中找到。 Jotne 的答案中的快速解决方法。

[1]: Posix standard, utility section, awk

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-27
    • 2010-11-02
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 2015-12-23
    相关资源
    最近更新 更多