Как определить в скрипте оболочки, будет ли этот скрипт продолжен после приостановки?

Как определить в скрипте оболочки, будет ли этот скрипт продолжен после приостановки?

У меня есть скрипт оболочки, который регулярно выполняется через cron/crontab. Я ввожу туда sleepкоманду на несколько минут:

sleep 5m # Waits 5 minutes.

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

Если мой компьютер выходит из спящего/приостановленного режима, я не хочу продолжать выполнение скрипта (так как компьютер может просто проснуться через 4 минуты и 59 секунд, и файлы еще не будут синхронизированы).

Как можно проверить в скрипте оболочки, что пробуждение из режима ожидания произошло более 5 минут назад?

(похоже, дата /var/log/pm-suspend.logне обновлена ​​в моей системе)

решение1

Прежде всего, отметим, что sleepэто не учитывает время отстранения.

Например, если вы выполните команду sleep 5m, затем приостановите работу компьютера, а затем через 4 минуты разбудите его, то sleepкоманда завершится через 9 минут после запуска. Он будет спать 5 минут без приостановки.

Учитывая это, я не думаю, что вам вообще нужен тот хак, который вы ищете. Ваш вопрос подразумевал противоположное, неверное предположение, а именно, что sleep 5mкоманда может спать в течение 4 минут и 59 секунд, которые компьютер провел в состоянии ожидания, и 1 секунды бодрствования.


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

Есть несколько системных часов, описанных в clock_gettime(2)руководстве.

Один из них — это CLOCK_MONOTONIC, это не учитывает время ожидания. Это значение в секундах, от некоторой произвольной начальной точки, выражающее количество времени, которое компьютер провел фактически бодрствующим.

Есть еще один, CLOCK_REALTIMEкоторый выражает реальное время мира. Однако он склонен к резким скачкам, если часы скорректированы, поэтому не является полностью надежным. Вместо этого давайте использовать CLOCK_BOOTTIME. Это значение в секундах, от некоторой произвольной начальной точки (предположительно, времени загрузки системы), включая время, проведенное компьютером в состоянии ожидания.

Вы можете распечатать эти два значения с помощью таких команд, как

python3 -c 'import time; print(time.clock_gettime(time.CLOCK_MONOTONIC))'
python3 -c 'import time; print(time.clock_gettime(time.CLOCK_BOOTTIME))'

(Существует также более простой синтаксис для получения монотонного времени; я намеренно выбрал синтаксис, который работает для обоих видов часов.)

В определенный момент запросите эти два значения и вычислите их разницу. В определенный другой момент сделайте это снова.

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

решение2

В одну сторону

Время последнего резюме должно быть доступно в systemdсистеме журналов, например:

journalctl -r | awk '/resume/ {print $0; exit}'

Таким образом, вы можете присвоить временную метку в short-isoформате переменной, например:

lr="$(journalctl -r -o short-iso | awk '/resume/ {printf "%s", $1; exit}')"

и добавьте к нему пять минут, одновременно преобразуя его в метку времени Unix, например:

lr5="$(date -d "$lr + 5 minutes" +'%s')"

и сравнить/оценить более позднюю и текущую временную метку Unix с помощью чего-то вроде (bashопределенный синтаксис):

if [[ "$(date +'%s')" -ge "$lr5" ]]
  then
    echo "Five minutes have passed since last resume."
    # Your command/s here
    fi

Другой путь

Вы можете создать свою собственную временную метку, поместив файл скрипта в /lib/systemd/system-sleep/каталог, используя этот шаблон:

#!/bin/sh

case "${1}" in
  pre)
    # Command(s)/script(s) to execute before system goes to sleep/hibernate
    # nothing
      ;;
  post)
    # Command(s)/script(s) to execute after system wakes up from sleep/hibernate
    # Save your timestamp e.g.:
    # /bin/date +'%s' > /home/user/timestamp.log
      ;;
esac

И используйте логику, похожую на первый способ, для анализа и оценки на основе временной метки из вашего собственного файла журнала.

Уведомление: Для использования второго способа запуска скриптов, которым требуется/зависит от сетевого подключения, см. первый раздел:Часть скрипта, связанная с сетью, не будет запущена в /lib/systemd/system-sleep.

Связанный контент