Bash 脚本:在循环内执行一次某件事,然后停止,但继续循环

Bash 脚本:在循环内执行一次某件事,然后停止,但继续循环

我有一个 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分别为:

  1. 100 和 1

    • 第一个模式已匹配,该模式与空代码块关联。不采取任何操作,并case返回到while
  2. 100 和 0

    • 第二个模式被匹配,它设置为 1 并使用参数调用$fullshell 函数pushBattery Charged
    • push()此处仅定义以根据目的组织代码。
  3. <=20 以及任何东西

    • 第三个模式匹配,$full设置为 0,并push使用 arg 调用Plug in Now
  4. 任何东西和 1

    • 最后一个模式已匹配并$full设置为 0。
  5. 还要别的吗

    • 没有匹配任何模式并且不采取任何操作。

总而言之,这意味着$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。如果percentprevious均为 100,则不打印消息。

鉴于您在后台运行此程序来监控电池,您应该尽量不要使用太多电量。尽量减少进程数量。

不是在 上循环true,而是在命令上循环sleep。这样,您可以sleep在脚本运行时(大多数情况下)通过终止命令来终止脚本。

缩进你的代码。块内的任何内容(dothen等)的左侧都应有更多的空白,且数量一致。

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

相关内容