Bash-Script: как проверить, является ли номер часа четным?

В сценарии bash (запускается каждые 30 минут) я хочу выполнять действие каждый четный час (и минут 0), поэтому я хочу проверить номер часа, четный он или нет. Поэтому я использую это:

        HEURE=$(date +"%H")
        MINUTES=$(date +"%M")
        HEURE_PAIRE = ""
        MINUTES_ZERO = ""
        [[ $((HEURE % 2)) -eq 0 ]] && HEURE_PAIRE = "OUI" || HEURE_PAIRE = "NON"
        [[ $MINUTES -eq 0 ]] && MINUTES_ZERO = "OUI" || MINUTES_ZERO = "NON"
        if [[ "${HEURE_PAIRE}" == "OUI" ]] && [[ "MINUTES_ZERO" == "OUI" ]]; then
            # My code
        fi

Но я получаю ошибку для этой строки (номер 170 в моем сценарии) [[ $((HEURE % 2)) -eq 0 ]] && HEURE_PAIRE = "OUI" || HEURE_PAIRE = "NON", когда это было 08:00, 08:30, 09:00, 09:30, но не для 10:00 или 10:30. Смотрите ошибку, которую я получаю:

/volume4/docker/_Scripts-DOCKER/driver-pkgctl-r8152-restart-reload.sh: line 170: 08: value too great for base (error token is "07")
/volume4/docker/_Scripts-DOCKER/driver-pkgctl-r8152-restart-reload.sh: line 170: 09: value too great for base (error token is "09")

Я ожидал, что это будет работать так: Для 08:0008%2 должно вернуть 0 в результате, доказывая, что час четный. Для 09:0009%2 должно вернуть 1 в результате, доказывая, что час еще не четный. Отсутствие ошибки

Я предполагаю, что это 0 перед 8 или 9... Но я не знаю, как это исправить.

Я нашел обходной путь с этим вопросом, добавив это:

HEURE=${HEURE#0}

Кажется, это работает.

Мой вопрос: есть ли лучший способ добиться того, чего я хочу?

Заранее спасибо.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
89
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Исправленный скрипт:

форсирующая база 10¹:

#!/bin/bash

heure=10#$(date +"%H") minutes=10#$(date +"%M")
if (( heure % 2 == 0 && minutes == 0 )); then
    # My code
fi

Другой способ использования расширений параметров POSIX

#!/bin/bash

heure=$(date +"%H") minutes=$(date +"%M")
if (( ${heure#0} % 2 == 0 && ${minutes#0} == 0 )); then
    # My code
fi

другой способ, используя crontab

*/30 * * * * /path/to/script

Не используйте переменные ВЕРХНЕГО регистра


((...)) и $((...)) — арифметические команды, которые возвращают статус выхода 0, если выражение не равно нулю, или 1, если выражение равно нулю. Также используется как синоним слова «пусть», если необходимы побочные эффекты (назначения). См. http://mywiki.wooledge.org/ArithmeticExpression


¹ В арифметических операциях с bash, есть ли ведущий 0 как 08, он обрабатывается как восьмеричное число. Чтобы заставить base10, я использую префикс 10# для часов и минут


Не нужно заключать кавычки в синтаксисе [[ ... ]], см. http://mywiki.wooledge.org/BashFAQ/031 и http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

Спасибо за вашу помощь. Сегодня я кое-чему научился :) Могу ли я отправить весь сценарий на проверку?

MilesTEG 16.04.2023 16:06

Не знаю, какой обзор вы имеете в виду

Gilles Quénot 16.04.2023 16:09

@MilesTEG: см.: codereview.stackexchange.com

Cyrus 16.04.2023 16:13

Упрощен для проверки кода

Gilles Quénot 16.04.2023 16:18

Просто, чтобы проверить, если это должно быть улучшено. Но прежде всего мне нужно перевести имена переменных в нижний регистр ^^ Ваш правильный скрипт не работает. Формат времени в командах даты не подходит. Это должно быть: bash heure=10#$(date +"%H") minutes=10#$(date +"%M") Потому что со строчными буквами h и m я получаю это (с поддельным временем): bash faketime '08:00:00' ./test.sh dim. 16 avril 2023 08:00:00 CEST heure is : 10#avril minutes is : 10#04 ./test.sh: ligne 12: ((: 10#avril : valeur trop grande pour la base (le symbole erroné est « 10#avril ») Строка 12 — это строка с проверкой по модулю.

MilesTEG 16.04.2023 16:20

Это опечатка, извиняюсь, исправляю

Gilles Quénot 16.04.2023 16:21

Еще один вопрос, связанный с предыдущим. У меня есть этот тест: if [[ "${gotify_always}" == "OUI" ]] || [ ${gotify_priority} -eq ${gotify_priority_error} ] || [ ${gotify_priority} -eq ${gotify_priority_fail} ] || { [ ${gotify_priority} -eq ${gotify_priority_success} ] && [[ "${heure_paire}" == "oui" ]] && [[ "${minutes_zero}" == "oui" ]]; }; then . Это правильно? PS: все остальные переменные являются строковыми переменными.

MilesTEG 16.04.2023 16:39

Напишите еще вопрос. Но в основном можно упростить

Gilles Quénot 16.04.2023 16:41

ПОКА это # в этом контексте не является началом комментария. Не уверен, почему это не так, но спасибо!

Ed Morton 16.04.2023 19:06

Новый вопрос сейчас невозможен, я нахожусь в бане вопросов... И я не могу улучшить свой первый вопрос, так как он был плохо задан, и я действительно не помню, что хотел спросить. PS: для возможности задания cron я уже поместил свой скрипт в планировщик задач DSM (Synology NAS). Итак, я думаю, он уже находится в задании cron каждые 30 минут. Мой скрипт должен выполняться каждые 30 минут, но только каждые 2 часа 00 минут, он будет отправлять уведомление о получении, или если есть ошибка или сбой.

MilesTEG 16.04.2023 22:59

@EdMorton # должен быть первым символом слова, обозначающим комментарий. См. правила 7, 8 и 9: pubs.opengroup.org/onlinepubs/9699919799/utilities/…

jhnc 18.04.2023 01:27

@EdMorton Я использую своего рода «приведение», чтобы избежать «bash», чтобы увидеть, например. 08 как восьмеричное. 10#08 «отлит» в базе 10

Gilles Quénot 18.04.2023 01:40

Альтернативный метод без использования арифметических выражений:

#!/bin/bash

hm=$(date +%H%M)
if [[ $hm = ?[02468]00 ]]; then
    # do stuff
fi

или в оболочке POSIX:

#!/bin/sh

hm=$(date +%H%M)
case $hm in
    ?[02468]00) do_stuff ;;
esac

или, с арифметикой Bash за одну операцию:

#!/bin/bash

if (( 10#$(date +%H%M) % 200 == 0 )); then
        echo "It is time" 
fi

Ваши решения аналогичны решениям @jhnc. Мне нравится тот, что для Баша. Кажется эффективным. Я ищу наиболее эффективный способ делать то, что я хочу, и таким образом, который я могу понять :)

MilesTEG 16.04.2023 23:06

@m-nejat-aydin: работает третий метод. Вы можете объяснить, пожалуйста?

MilesTEG 17.04.2023 11:09

Установка базы — хороший метод для bash.

Для оболочек POSIX, которые не поддерживают это, есть другие варианты.

Префикс с ненулевой цифрой:

heure=$(date +1%H)
...

Удалите ведущий ноль:

heure=$(date +%H)
heure=${heure#0}
...

Сравните по тексту:

heure=$(date +%H)
...
case $heure in ?[02468]) ... ;; esac
...

Ваше второе предложение — это то, что я использовал до того, как @gilles-quénot дал первый ответ. Ваше второе предложение работает 13 часов, 14 часов... 23 часа? Я живу во Франции, где время идет 24 часа, а не 12 часов утра/вечера.

MilesTEG 16.04.2023 23:03

Простой способ узнать это попробовать: например. h=02; echo ${h#0}; h=14; echo ${h#0}

jhnc 17.04.2023 01:23

оно работает. А как насчет метода "Сравнить по тексту"?

MilesTEG 17.04.2023 11:05

что происходит, когда вы пытаетесь это сделать?

jhnc 17.04.2023 15:45

У меня нет времени, чтобы попробовать это, пока нет. Но я всегда стараюсь понять команду, прежде чем ее использовать. И здесь я не понимаю, что произойдет с 2-значным часом, например, 13 или 23…

MilesTEG 17.04.2023 23:52

Во-первых, это плохо:

HEURE=$(date +"%H")
MINUTES=$(date +"%M")

Время может переключаться, например. с 10:59 до 11:00 между ними. А потом вы ошибаетесь в 10:00.

Используйте либо

time=$( date +%H:%M )
HEURE = "${time%:*}"
MINUTES = "${time#*:}"

... или ...

time=$( date +%s )
HEURE=$( date -d@$time +%H )
MINUTES=$( date -d@$time +%M )

В обоих вариантах вы получаете время только один раз. Во втором примере вы получите время эпохи, а затем вычислите час в минуту от этого времени. Первый пример кажется более эффективным.

Затем замените [[ $((HEURE % 2)) -eq 0 ]] на (( !( 10#$HEURE % 2 ))) или (( ( 10#$HEURE % 2 ) == 0 )). Префикс 10# задает оценку как десятичное число.

Последнее замечание: в общем случае используйте строчные буквы или смешанный регистр для имен локальных переменных.

Неплохо подмечено. Время может немного измениться, да. Но мой скрипт запускается DSM (Synology Nas) в 00:00 и далее каждые 30 минут. Я предполагаю, что он будет запущен в 00:00:00 или через несколько (милли) секунд. И это не проблема в тестах, сделанных здесь. Но у вас есть точка зрения здесь. Желательно получать часы и минуты одновременно. Я это реализую. Спасибо.

MilesTEG 17.04.2023 12:20

В числовом контексте строки, начинающиеся с нуля, считаются восьмеричными. Следовательно, 08 ошибочно.

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

if [[ $(date +%HM) == ?[02468]00 ]]
then
  ....
fi

Это то, что @m-nejat-aydin ответил перед вами. Это похоже на регулярное выражение, но для bash? Не могли бы вы объяснить, как это работает?

MilesTEG 17.04.2023 23:56

Это не регулярное выражение, а глобальный шаблон. В [[ E1 == E2 ]] E2 рассматривается как шаблон глобуса, а E1 сопоставляется с ним. Синтаксис подстановки объясняется в разделе «Расширение пути» на странице руководства bash. Будьте осторожны: если E2 заключен в кавычки, сопоставление с образцом отключено. Вы также можете использовать сопоставление регулярных выражений (bash использует расширенное регулярное выражение POSIX). В этом случае используется синтаксис [[ E1 =~ E2 ]].

user1934428 18.04.2023 07:51

Другие вопросы по теме