如何编写一个awk
可以根据输入文件中的行所要求的内容进行添加或减去的脚本?我弄清楚了如何仅进行加法或减法,但不是在一个脚本中进行任一/或。
例如,我想要这个输入:
ADD 5,10,20
SUB 30,5,20
产生这个输出:
35
-55
这是我到目前为止所写的:
#!/bin/awk
BEGIN {
FS=","
}
{
for(i=1;i<=NF;i++)
sum+=$i;
print sum; sum=0}
但是,显然,它只进行加法,甚至没有获得所有数字。
答案1
一些技巧:
- 使用空格或逗号作为字段分隔符:
FS = "[ ,]"
- 然后像你一样将数字相加,除了以
i = 2
- 如果第一个字段是
SUB
,则将总和乘以 -1
答案2
这是实现 Glenn Jackman 算法的一种方法,使用关联数组来保存乘法值(1 或 -1):
$ awk -F ',|[[:blank:]]+' '
BEGIN {
mult["ADD"] = 1;
mult["SUB"] = -1;
};
$1 ~ /^(ADD|SUB)$/ {
sum = 0;
for (i=2; i <= NF; i++) { sum += $i };
print sum * mult[$1];
}' input.txt
35
-55
这也提供了添加其他关键字的框架的开始 - 例如“MULT”或“DIV”或“EXP”(对于这些,您将使用而不是sum=$2
启动 for 循环)。i=3
i=2
答案3
$ awk -F'[ ,]' '{sum=0; for (i=2; i<=NF; i++) sum+=$i; print ($1=="ADD" ? 1 : -1) * sum}' file
35
-55
如果您必须支持更多操作而不仅仅是 ADD 和 SUB,例如:
$ cat file
ADD 5,10,20
SUB 30,5,20
MULT 2,3,4
DIV 20,2,2
您可以使用 GNU awk 并为您想要支持的每个操作定义函数并间接调用它们:
$ cat tst.awk
function ADD(n) { sum += n }
function SUB(n) { sum -= n }
function DIV(n) { if (n==0) { printf "%s[%d]: Divide by zero error in %s\n", FILENAME, FNR, $0 | "cat>&2"; exit 1 } sum /= n }
function MULT(n) { sum *= n }
BEGIN { FS="[ ,]" }
{
op = $1
sum = (op=="SUB" ? -1 : 1) * $2
for (i=3; i<=NF; i++) {
@op($i)
}
print sum
}
$ awk -f tst.awk file
35
-55
24
5
我必须使用特殊情况的“SUB”才能从您提供的输入中获取您想要的输出,因为它的处理方式与其余的不同(即从零减去的所有数字,而不是所有数字相加/相乘/相除) 。如果 SUB 行上的第一个数字是-30
或 ,0
那么30
所有操作都可以以完全相同的方式处理,例如:
$ cat file
ADD 5,10,20
SUB 0,30,5,20
MULT 2,3,4
DIV 20,2,2
$ cat tst.awk
function ADD(n) { sum += n }
function SUB(n) { sum -= n }
function DIV(n) { if (n==0) { printf "%s[%d]: Divide by zero error in %s\n", FILENAME, FNR, $0 | "cat>&2"; exit 1 } sum /= n }
function MULT(n) { sum *= n }
BEGIN { FS="[ ,]" }
{
op = $1
sum = $2
for (i=3; i<=NF; i++) {
@op($i)
}
print sum
}
$ awk -f tst.awk file
35
-55
24
5