awk 是否可以根据第一个值对记录中的值进行不同的处理?

awk 是否可以根据第一个值对记录中的值进行不同的处理?

我对 awk 还比较陌生。我正在创建一个 awk 脚本,它将读取具有以下一般格式的文件:

NAME firstName lastName
PAY cost numberOfPayments
END

我的文件看起来会像这样:

NAME Jane Doe
PAY 5.00 2
PAY 2.00 10
END
NAME John Doe
PAY 10.00 5
PAY 4.00 3
PAY 1.00 20
END

NAME并且之间的付款金额END可以有所不同,并且可以有多个名称(这只是一个示例)。

这是我的 awk 脚本:

# !/bin/awk

BEGIN { total=0; RS = "END"; }
{
    if (match($1, "NAME")) {
        print $2;
    }
    if (match($1, "SAVE")) {
        total = total + ($2 * $3);
        print total;
    }
}

第一个值应该识别我们正在执行的操作(PAYNAME)。基于此,我应该打印NAME或找到通过将成本乘以付款次数得出的总金额。END是我用来表示这是该特定客户记录的结束。

这个特定文件的输出应该是:

Jane 30
John 82

我尝试了几种方法,但似乎无法获得所需的输出。如能得到任何帮助,我将不胜感激!

答案1

首先,代码:

#!/usr/bin/awk -f

$1 == "NAME" { printf "%s ", $2 }
$1 == "PAY" { total += $2 * $3 }
$1 == "END" { print total; total = 0 }

如果您调用该脚本tally,用 将其标记为可执行文件chmod +x tally,并且您位于包含该脚本的目录中,则可以在输入文件上运行它file和:

./tally file

在您显示的输入文本中,它给出了您想要的输出:

Jane 30
John 82

您尚未说明当有多个名称且中间没有中间词时输出的内容END,但我假设您希望输出每个名称的名字。考虑以下输入文件:

NAME Jane Doe
NAME Clark Kent
PAY 5.77 9
END
NAME John Doe
PAY 14.22 6
NAME Linda Lee Danvers
PAY .25 4
END

输出结果如下:

Jane Clark 51.93
John Linda 86.32

它的作用以及原因:

在您尝试解决的问题中,从概念上来说,每个应被视为记录的内容都是多行的“节”,其中一行可能由多个字段组成。因此,每个数据都有三个“坐标”:⟨节、行、场⟩

但 AWK 的基本抽象是⟨记录,字段⟩。AWK 仍然是解决此问题的不错选择,但您必须决定如何将问题的自然抽象映射到工具直接支持的抽象。在您的代码中,看起来您可能试图将每个节视为单个记录,因为您已创建END输入记录分隔符 ( RS = "END")。这可以正常工作,我希望发布其他答案来展示如何操作。但我建议将awk每一行都视为一条记录。

原因是已经有另一种方式来思考你的输入数据:作为命令,每行一个,其中:

  1. 您的NAME命令输出其后面的单词。从概念上讲,这是名字。
  2. 您的PAY命令将乘积累加到一个变量中total。具体来说,它将后面的两个值相乘,然后增加total该值。
  3. 您的END命令将打印total,结束该行,并重置total回零。

逐行说明其工作原理:

#!/usr/bin/awk -f

在 Ubuntu 中,awk位于/usr/bin而不是/bin。该-f标志是必需的(在任何操作系统上),以告诉 AWK 下一个参数,这是脚本本身的文件名,应该被解释为一个脚本,而不是要处理的输入文件的名称。

没有BEGIN规则

您可以创建一个并tally = 0在其中设置,但您不需要这样做,因为 AWK 允许对未初始化的变量进行算术运算并将它们视为零。(如果您正在运行,那么您可能希望明确包含赋值以避免出现“引用未初始化的变量”警告。)我在这里放了一个空行,但您不必这样做。gawk --lint -f tally file

$1 == "NAME" { printf "%s ", $2 }

当第一个字段为 时NAME,将第二个字段打印$2为一个字符串 ( %s),后跟一个空格。

$1 == "PAY" { total += $2 * $3 }

当第一个字段为 时PAY,将 的值增加total第二个字段和第三个字段的乘积。

$1 == "END" { print total; total = 0 }

当第一个字段为 时END,打印 的值total。该print语句会自动附加输出记录分隔符,即新队因为您还没有进行ORS其他设置。然后将其total重新设置为零,以准备下一个节(如果有)。

相关内容