我不是一个深入的 shell 脚本行家,我知道基础知识,并且愿意接受针对我的问题的建议,我需要编写一个每天 24 小时运行的脚本,但老实说,我什至不知道从哪里开始,知道如何根据下面的情况组装这个脚本吗?
我有以下场景,示例 1(这就是今天的情况)和示例 2(预期结果)
实施例1
#Price_Notification_ProductABC 价格:0.006813 变化:+1.6% 计数数量:1 #Price_Notification_ProductABC 价格:0.006969 变化:+2.3% 计数数量:2 #Price_Notification_ProductABC 价格:0.007060 变化:+1.3% 计数数量:3 #Price_Notification_ProductABC 价格:0.007300 变化:+3.4% 计数数量:4 #Price_Notification_ProductABC 价格:0.007453 变化:+2.1% 计数数量:5
实施例2
#Price_Notification_ProductABC 价格:0.006813 变化:+1.6% 计数数量:1 #Price_Notification_ProductABC 价格:0.006969 变化:+3.9% 计数数量:2 #Price_Notification_ProductABC 价格:0.007060 变化:+5.2% 计数数量:3 #Price_Notification_ProductABC 价格:0.007300 变化:+8.6% 计数数量:4 #Price_Notification_ProductABC 价格:0.007453 变化:+10.7% 计数数量:5
要求:
1-项目 #Price_Notification_ProductABC 不是固定项目,搜索可以返回多个产品(Price_Notification_ProductABC、#Price_Notification_ProductXYZ、#Price_Notification_Product123 等),因此,为了使其正常工作,我认为有必要使用 grep 进行匹配收到的关于该项目的第一个通知
2- 价格项没有预定义的小数位,它可以采用格式 Price: 0.006813 Price: 1.256 Price: 524.354 等,它是动态的
3- 更改项目是最复杂的解释,通知返回包含始终为小数的数字的百分比,如示例 1 所示,
- 我想要一个过滤器,它可以增量地进行计算总和,如示例 2 所示
- 此增量总和必须始终添加上一个通知的百分比 + 当前通知的百分比
- 但为此需要有一些条件: 当前通知的 Price 项的值必须始终大于前一个通知的值,如果不满足此条件,则包含通知总和/百分比的循环/过滤器必须被重置,从而开始新的后续通知周期
4-计数项目,我真的不知道如何处理这个项目,因为计数也是动态的,并且总是每小时重置为 0,但我愿意接受有关如何处理这个项目的建议
请注意,我通过这种方式获取此信息,对此我无能为力,我正在尝试构建一个根据收到的信息为我服务的脚本。
我还需要解决两个标准/条件,当这两个条件之一存在时,必须重置增量/增加百分比计算,开始新的循环
1- 百分比需要增量计算,在一个通知与另一个通知之间的 0 到最多 30 分钟的窗口内,从第 31 分钟开始,需要重置/重新启动百分比的增量计算,开始新的通知计算周期
2- 从价格项收到的最后一个通知不能包含低于前一个通知的值,例如,我又收到了三个新通知(计数编号:6、计数编号:7 和计数编号:8)
#Price_Notification_ProductABC 价格:0.007023 变化:+1.8% 计数数量:6 #Price_Notification_ProductABC 价格:0.007184 变化:+2.3% 计数数量:7 #Price_Notification_ProductABC 价格:0.007328 变化:+3.3% 计数数量:8
在此示例中,由于Price: 0.007023
通知计数编号:6 的项目的值低于Price: 0.007453
前一个通知计数编号:5 的项目的值,因此我需要启动一个新循环,将之前完成的所有计算清零/重新启动。
它应该看起来像这样:
#Price_Notification_ProductABC 价格:0.007023 变化:+1.80% 计数数量:6 #Price_Notification_ProductABC 价格:0.007184 变化:+4.10% 计数数量:7 #Price_Notification_ProductABC 价格:0.007328 变化:+7.40% 计数数量:8
有什么建议来解决这个其他情况吗?
谢谢!
答案1
awk
这并不像看起来那么困难,在或中相当容易做到perl
。
使用perl:
$ perl -lpe 'if (/^#Price_Notification_Product/) {
$prod = $_;
} elsif (/^change: ([^%]*)%/) {
$products{$prod} += $1;
$_ = "change: +$products{$prod}%";
}' input.txt
#Price_Notification_ProductABC
Price: 0.006813
change: +1.6%
Count Number: 1
#Price_Notification_ProductABC
Price: 0.006969
change: +3.9%
Count Number: 2
#Price_Notification_ProductABC
Price: 0.007060
change: +5.2%
Count Number: 3
#Price_Notification_ProductABC
Price: 0.007300
change: +8.6%
Count Number: 4
#Price_Notification_ProductABC
Price: 0.007453
change: +10.7%
Count Number: 5
- perl 的
-l
选项打开自动处理行结束符(例如,从输入中去除换行符,将它们添加到 byprint
语句的输出中) - 该
-p
选项使其像 sed 一样工作(即读取每个输入行并在任何处理后自动打印它) -e
告诉 perl 下一个 arg 是要执行的脚本。
该脚本读取每个输入行,如果该行以“#Price_Notification_Product”开头,则将当前行存储在变量中$prod
。
否则,如果该行以“change:”开头,则:
使用正则表达式捕获提取更改的值,并将该值添加到名为 的散列(也称为“关联数组”)中
%products
。哈希值的关键是产品名称 ($prod
)。它使用散列,以便可以处理输入中任意数量的产品名称 - 只要
#Price_Notification_Product...
每个产品的行是唯一且一致的。每个产品名称的累计总数将被独立跟踪。更改当前行(变量
$_
),使其具有该产品的当前累计总计。顺便说一句,如果您希望“change:”行在小数点之前和/或之后具有固定位数,您可以使用
sprintf
.例如,将该$_ = "change...."
行更改为:$_ = sprintf("change: %7.2f%%", $products{$prod}); s/(\d)/+$1/;
这将输出“更改”行,如下所示:
change: +1.60% change: +3.90% change: +5.20% change: +8.60% change: +10.70%
所有输入行都会被打印,无论它们是否已被修改。
输入可以来自文件(例如input.txt
我使用过的文件)或来自标准输入(例如来自 的管道tail -f
)。
顺便说一句,我刚刚想到,当产品的计数重置为零时,您可能希望将产品的累计总数重置为零。如果是这种情况,请更改最后一行:
}' input.txt
对此:
} elsif (/^Count Number: 0$/) {
$products{$prod} = 0;
}' input.txt
与独立脚本相同:
#!/usr/bin/perl -lp
if (/^#Price_Notification_Product/) {
$prod = $_;
} elsif (/^change: ([^%]*)%/) {
$products{$prod} += $1;
$_ = "change: +$products{$prod}%";
}
如果您的 Perl 解释器位于不同的位置,您需要调整#!
行以引用正确的完整路径。
将其另存为,例如./script.pl
,使用 使其可执行chmod +x script.pl
,然后运行它,如下所示:
$ ./script.pl input.txt
或者
$ perl -lp ./script.pl input.txt
awk 版本,perl 版本的直接翻译,但我们还必须使用从每个“change:”行的第二个字段中gsub()
删除+
和符号:%
$ awk '
/^#Price_Notification_Product/ {
prod = $0;
}
/^change: / {
gsub(/[+%]/,"",$2);
products[prod] += $2;
$2 = "+" products[prod] "%"
}
1' input.txt
awk 脚本最后一行1
的 不是拼写错误 - 这就是告诉 awk 始终打印当前行,无论它是否已被修改(awk 脚本本质上是一系列 PATTERN ACTION 规则,如果 PATTERN 评估为 true 那么ACTION 1
评估为 true,默认操作为{print}
)