![awk 是否可以根据第一个值对记录中的值进行不同的处理?](https://linux22.com/image/896018/awk%20%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%80%BC%E5%AF%B9%E8%AE%B0%E5%BD%95%E4%B8%AD%E7%9A%84%E5%80%BC%E8%BF%9B%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%9A%84%E5%A4%84%E7%90%86%EF%BC%9F.png)
我对 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;
}
}
第一个值应该识别我们正在执行的操作(PAY
与NAME
)。基于此,我应该打印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
每一行都视为一条记录。
原因是已经有另一种方式来思考你的输入数据:作为命令,每行一个,其中:
- 您的
NAME
命令输出其后面的单词。从概念上讲,这是名字。 - 您的
PAY
命令将乘积累加到一个变量中total
。具体来说,它将后面的两个值相乘,然后增加total
该值。 - 您的
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
重新设置为零,以准备下一个节(如果有)。