我有一个 Bash 脚本,用于检查我的笔记本电脑电池并向我发送 Android 通知(通过 Shuttle,我编写的一个 Bash 脚本,用作 Pushbullet API 的 cli 接口)。它工作得很好,但当电池电量达到 100% 时,它会反复通知我拔掉笔记本电脑的插头。相反,我宁愿它只通知我一次 100% 充电,然后就这样了(即继续检查但不通知)。然而,我确实希望它在电池电量不足时反复通知我,以便我记得插入笔记本电脑(这就是它目前的作用)。
我认为这可以在循环内使用 continue 和 break 命令,但我不确定这是否是我想要的(我对这些不太熟悉)。
不管怎样,我很感激关于如何使用 Bash 最好地实现这一点的建议。我怀疑这很简单,但由于某种原因我没有得到它。
这是我的脚本:
#! /bin/bash
while true;
do
percent=$(acpi | awk '{ print $4}' | sed -e 's/%//g' | sed -e 's/,//g')
if [ "$percent" -le "20" ];
then
shuttle push note Chrome "Aurora: Plug in now" "Battery is at $percent percent"
fi
if [ "$percent" -eq "100" ];
then
shuttle push note Chrome "Aurora: Battery charged" "Battery is at $percent percent"
fi
sleep 7m
done
答案1
push(){
shuttle push note Chrome \
"Aurora: $1" \
"Battery is at $percent percent"
}
full=0
while percent=$(acpi | awk '{ print $4}' | sed 's/[,%]//g')
do case $percent:$full in
(100:1) ;; (100:0)
full=1
push 'Battery charged';;
(?:*|1?:*|20:*)
full=0
push 'Plug in Now';;
(*1) full=0
esac
done
shell 的case
语句允许您根据 shell 模式是否可以与 shell 扩展的值匹配来执行任意代码块。通过这种方式,您可以非常简单地处理同一测试的多种可能结果。
$percent
在上面,我将和的值连接$full
在:
冒号分隔符上,这是我最初从 Stephane Chazelas 那里学到的一种技术,即使从那以后我自己已经变得相当擅长了。由于执行的代码需要依赖于这两个值,因此同时测试这两个值是最简单的解决方案。
case
模式块按从第一个到最后一个的顺序进行评估。一旦模式匹配,就会执行相关代码并case
返回。第一个匹配的模式也是最后一个被评估的模式。
$percent
因此,如果和的值$full
分别为:
100 和 1
- 第一个模式已匹配,该模式与空代码块关联。不采取任何操作,并
case
返回到while
。
- 第一个模式已匹配,该模式与空代码块关联。不采取任何操作,并
100 和 0
- 第二个模式被匹配,它设置为 1 并使用参数调用
$full
shell 函数push
Battery Charged
push()
此处仅定义以根据目的组织代码。
- 第二个模式被匹配,它设置为 1 并使用参数调用
<=20 以及任何东西
- 第三个模式匹配,
$full
设置为 0,并push
使用 arg 调用Plug in Now
。
- 第三个模式匹配,
任何东西和 1
- 最后一个模式已匹配并
$full
设置为 0。
- 最后一个模式已匹配并
还要别的吗
- 没有匹配任何模式并且不采取任何操作。
总而言之,这意味着$full
仅在必要时设置,仅当为 0 且为 100 或为任何值且<=20push()
时才调用。$full
$percent
$full
$percent
所有这些都会对你已有的有所改善。但真正的问题是:
percent=$(acpi | awk '{ print $4}' | sed 's/[,%]//g')
while true
像在is中一样分叉多次难以置信浪费。你必须想出另一种方法来做到这一点。
答案2
怎么样:
if [ "$percent" -eq 100 ] && [ "$full_flag" -eq 0 ];
then
shuttle push note Chrome "Aurora: Battery charged" "Battery is at $percent percent"
full_flag=1
fi
if [ "$percent" -lt 100 ];
then
full_flag=0
fi
答案3
continue
跳转到循环的下一次迭代。break
完全退出循环。如果您想对未来的迭代产生一些影响,那么这两种方法都没有用。为此,您需要记住某些东西必须表现不同的信息。记住一些信息的方法是将其存储在变量中。
完成您想要的操作的一种方法是将 的先前值存储percent
在变量中previous
。如果percent
和previous
均为 100,则不打印消息。
鉴于您在后台运行此程序来监控电池,您应该尽量不要使用太多电量。尽量减少进程数量。
不是在 上循环true
,而是在命令上循环sleep
。这样,您可以sleep
在脚本运行时(大多数情况下)通过终止命令来终止脚本。
缩进你的代码。块内的任何内容(do
、then
等)的左侧都应有更多的空白,且数量一致。
previous=
while sleep 7m
do
percent=$(acpi | awk '{ gsub(/[^ 0-9]/, ""); print $4 }')
if [ "$percent" -le "20" ]; then
shuttle push note Chrome "Aurora: Plug in now" "Battery is at $percent percent"
elif [ "$percent" -eq "100" ] && [ "$previous" -ne "100" ]; then
shuttle push note Chrome "Aurora: Battery charged" "Battery is at $percent percent"
fi
done