Bash

優化 while 循環

  • September 27, 2019

我創建了一個迷你腳本,只需按一下按鈕即可重新啟動我的 Raspberry Pi。該腳本簡單地使用wiringPi(gpio 命令)將pin 0(Raspberry Pi 標準編號順序中的pin 17)設置為輸入,然後讀取該值直到它為1(即按下或按住按鈕時)。

這是我的腳本:

gpio mode 0 in

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

該腳本工作正常,一切正常。

但是,對於那些不熟悉 Pi 的人來說,它的硬體資源非常有限(包括 512 MB 記憶體),可以很容易地被我正在使用的循環所消耗。

我在這裡想要實現的是為 bash 找到另一種方法來找出值何時從0變為 ,1而不必為它專門設置一個更像無條件循環的方法。這是可行的嗎?請分享你的想法。

分析和現代解決方案

該腳本是一個繁忙的循環:它不斷地反复讀取 GPIO 引腳。它不會消耗太多記憶體,但會使 CPU 保持忙碌。

您應該將 GPIO 引腳設置為邊緣模式。該gpio實用程序有一個wfi(等待中斷)命令,可用於對邊沿觸發作出反應。(gpio wfi問問題時不存在。)

set -e
gpio mode 0 in
gpio wfi 0 rising
echo password | sudo -S reboot

一個 Python 解決方案

有一個用於 GPIO 訪問的 Python 庫,它支持邊緣模式。這是一些完全未經測試的 Python 程式碼,它們應該可以滿足您的需求。

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

額外的外殼提示

(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 ""

請注意,如果 sudoers 文件中有相同使用者的條目需要密碼,則該NOPASSWD條目必須緊隨其後。

一旦觸發重新啟動,您無需中斷循環,系統無論如何都會停止。

如果您決定繼續使用這個 shell 腳本,並且您的版本gpio太舊而無法使用wfi子命令,那麼這裡有一個改進的版本,它每秒只檢查按鈕狀態。請注意,由於 pin 每秒僅讀取一次,這意味著您需要按住按鈕至少一秒鐘以確保事件被拾取。

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

引用自:https://unix.stackexchange.com/questions/83308