优化“while”循环

Fad*_*ass 9 bash shell-script raspberry-pi

我创建了一个迷你脚本,只需按一下按钮即可重新启动我的 Raspberry Pi。该脚本简单地使用wiringPi(gpio命令)将引脚0(Raspberry Pi标准编号顺序中的引脚17)设置为输入,然后读取该值直到为1(即按下或按住按钮时)。

这是我的脚本:

gpio mode 0 in

while (true)
do
        if [ `gpio read 0` -eq 1 ]
        then
                echo password | sudo -S reboot
                break
        fi
done &
Run Code Online (Sandbox Code Playgroud)

该脚本工作正常,一切正常。

然而,对于那些不熟悉 Pi 的人来说,它带有非常有限的硬件资源(包括 512 MB 的内存),很容易被我正在使用的循环消耗掉。

我在这里试图实现的是为 bash 找到另一种方法来找出值何时从0变为 ,1而不必为它专门提供一个更像是无条件循环的方法。这是可行的吗?请分享您的想法。

Gil*_*il' 12

分析和现代解决方案

该脚本是一个繁忙的循环:它一遍又一遍地读取 GPIO 引脚。它不会消耗太多内存,但会使 CPU 保持忙碌。

您应该将 GPIO 引脚设置为边缘模式。该gpio实用程序有一个wfi(等待中断)命令,您可以使用该命令对边沿触发做出反应。(gpio wfi提出问题时不存在。)

set -e
gpio mode 0 in
gpio wfi 0 rising
echo password | sudo -S reboot
Run Code Online (Sandbox Code Playgroud)

一个 Python 解决方案

有一个用于 GPIO 访问Python 库,它支持边缘模式。这是一些完全未经测试的 Python 代码,它们应该可以满足您的需求。

#!/usr/bin/env python
import os
from RPi import GPIO
GPIO.wait_for_edge(0, GPIO.RISING)
system("sudo reboot")
Run Code Online (Sandbox Code Playgroud)

额外的外壳提示

(true)可以只写true. 括号创建一个子进程,这是完全没有必要的。

`gpio read 0`应该是双引号。如果没有引号,命令的输出将被视为文件名通配符模式列表。使用双引号,命令的输出被视为字符串。始终在命令替换和变量替换周围加上双引号:"$(some_command)", "$some_variable". 此外,您应该使用语法$(…)而不是`…`: 它具有完全相同的含义,但是当命令复杂时,反引号语法有一些解析怪癖。因此:if [ "$(gpio read 0)" -eq 1 ]

不要将 root 密码放在脚本中。如果脚本以 root 身份运行,则根本不需要 sudo。如果脚本不是以 root 身份运行,则授予运行脚本的用户运行的权限,sudo reboot而无需提供密码。运行visudo并添加以下行:

userwhorunsthescript ALL = (root) NOPASSWD: /sbin/reboot ""
Run Code Online (Sandbox Code Playgroud)

请注意,如果 sudoers 文件中有同一个用户需要密码的NOPASSWD条目,则该条目必须在后面。

一旦触发重新启动,您无需中断循环,系统无论如何都会停止。

如果您决定继续使用这个 shell 脚本,并且您的版本gpio太旧而无法使用wfi子命令,这里有一个改进的版本,它每秒只检查一次按钮状态。请注意,由于引脚每秒仅读取一次,这意味着您需要按住按钮至少一秒钟以确保事件被拾取。

gpio mode 0 in
while sleep 1; do
    if [ "$(gpio read 0)" -eq 1 ]; then
        reboot
    fi
done &
Run Code Online (Sandbox Code Playgroud)