Оптимизация цикла while

Я создал мини-скрипт для перезагрузки моей малины Pi при нажатии кнопки. Сценарий просто использует команду wiringPi (команда gpio) для установки вывода 0 (вывод 17 в стандартном порядке нумерации малины Pi) для ввода, а затем считывает значение до тех пор, пока оно не станет одним (то есть, когда кнопка нажата или удерживается нажатой).

Вот мой сценарий:

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

Скрипт работает отлично и все.

Тем не менее, для тех из вас, кто не знаком с Pi, он поставляется с очень ограниченными аппаратными ресурсами (включая 512 МБ памяти), которые могут быть легко использованы циклом, как тот, который я использую.

То, что я пытаюсь достичь здесь, – найти другой способ для bash, чтобы узнать, когда значение изменилось с 0 на 1 не выделяя для него более безусловный цикл. Это выполнимо? Поделитесь своими идеями.

  • Переключение пользователей с помощью sudo или su в сценарий оболочки
  • Практическое использование команды «shift» shell builtin?
  • Может ли Bash Variable Expansion выполняться непосредственно при вводе пользователя?
  • Использование find в unix для странных имен файлов / каталогов
  • Сценарий оболочки не отображает последнюю строку stdout на экране без ввода пользователем
  • Как выйти из цикла bash с клавиатуры?
  • Убедитесь, что переменная имеет определенное количество пробелов
  • Терминал не вызывает «then», сообщает синтаксическую ошибку, а команда не найдена
  • 3 Solutions collect form web for “Оптимизация цикла while”

    Анализ

    Сценарий занят: он продолжает считывать контакты GPIO снова и снова. Он не потребляет много памяти, но он заставляет процессор загружаться.

    Вы должны установить контакт GPIO в крайнем режиме. Автор WiringPi рассматривает возможность добавления команды wait к утилите gpio но в настоящее время нет способа реагировать на триггер edge из сценария оболочки.

    Решение Python

    Существует библиотека Python для доступа к GPIO , которая поддерживает режим edge. Вот какой-то полностью непроверенный код 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_command)" , "$some_variable" . Кроме того, вы должны использовать синтаксис $(…) а не `…` : он имеет точно такое же значение, но синтаксис backquote имеет некоторые parsing quirks, когда команда сложна. Таким образом: if [ "$(gpio read 0)" -eq 1 ]

    Не помещайте пароль root в скрипт. Если скрипт работает от имени root, вам вообще не нужен sudo. Если сценарий не запущен как root, дайте пользователю запустить сценарий для разрешения sudo reboot без предоставления пароля. Запустите visudo и добавьте следующую строку:

     userwhorunsthescript ALL = (root) NOPASSWD: /sbin/reboot "" 

    Обратите внимание, что если в файле sudoers, который требует пароль, для одного и того же пользователя NOPASSWD запись, запись NOPASSWD должна появиться после.

    Когда вы запускаете перезагрузку, вам не нужно разрывать цикл, система все равно остановится.

    Если вы решили использовать этот сценарий оболочки, вот улучшенная версия, которая проверяет только состояние кнопки каждую секунду. Обратите внимание, что поскольку штырь считывается только один раз в секунду, это означает, что вам нужно удерживать кнопку нажатой не менее одной секунды, чтобы убедиться, что событие поднято.

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

    То, что у вас есть, называется циклом занятости . Ваша петля не будет потреблять почти никакой памяти, но она будет потреблять много CPU. Обычно это смягчается путем добавления sleep к телу цикла.

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

    Избавление от цикла занятости будет зависеть от того, что делает gpio . Существуют системные вызовы, такие как select() , которые могут блокироваться до тех пор, пока дескриптор файла не будет готов.

    Что касается эффективности, () вокруг true команды фактически выполняет true в подоболочке. Это не требуется и может быть лучше выражено следующим:

     while (( $(gpio read 0) != 1 )); do sleep 1 done echo passowrd | sudo -S reboot 

    Попробуйте следующее:

     while ! gpio read 0 ; do sleep 1 done echo password | sudo -S reboot 
    Linux и Unix - лучшая ОС в мире.