В сценарии 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:00
08%2
должно вернуть 0
в результате, доказывая, что час четный.
Для 09:00
09%2
должно вернуть 1
в результате, доказывая, что час еще не четный.
Отсутствие ошибки
Я предполагаю, что это 0
перед 8
или 9
... Но я не знаю, как это исправить.
Я нашел обходной путь с этим вопросом, добавив это:
HEURE=${HEURE#0}
Кажется, это работает.
Мой вопрос: есть ли лучший способ добиться того, чего я хочу?
Заранее спасибо.
форсирующая база 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: см.: codereview.stackexchange.com
Упрощен для проверки кода
Просто, чтобы проверить, если это должно быть улучшено. Но прежде всего мне нужно перевести имена переменных в нижний регистр ^^ Ваш правильный скрипт не работает. Формат времени в командах даты не подходит. Это должно быть: 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 — это строка с проверкой по модулю.
Это опечатка, извиняюсь, исправляю
Еще один вопрос, связанный с предыдущим. У меня есть этот тест: 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: все остальные переменные являются строковыми переменными.
Напишите еще вопрос. Но в основном можно упростить
ПОКА это #
в этом контексте не является началом комментария. Не уверен, почему это не так, но спасибо!
Новый вопрос сейчас невозможен, я нахожусь в бане вопросов... И я не могу улучшить свой первый вопрос, так как он был плохо задан, и я действительно не помню, что хотел спросить. PS: для возможности задания cron я уже поместил свой скрипт в планировщик задач DSM (Synology NAS). Итак, я думаю, он уже находится в задании cron каждые 30 минут. Мой скрипт должен выполняться каждые 30 минут, но только каждые 2 часа 00 минут, он будет отправлять уведомление о получении, или если есть ошибка или сбой.
@EdMorton #
должен быть первым символом слова, обозначающим комментарий. См. правила 7, 8 и 9: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
@EdMorton Я использую своего рода «приведение», чтобы избежать «bash», чтобы увидеть, например. 08 как восьмеричное. 10#08
«отлит» в базе 10
Альтернативный метод без использования арифметических выражений:
#!/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. Мне нравится тот, что для Баша. Кажется эффективным. Я ищу наиболее эффективный способ делать то, что я хочу, и таким образом, который я могу понять :)
@m-nejat-aydin: работает третий метод. Вы можете объяснить, пожалуйста?
Установка базы — хороший метод для 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 часов утра/вечера.
Простой способ узнать это попробовать: например. h=02; echo ${h#0}; h=14; echo ${h#0}
оно работает. А как насчет метода "Сравнить по тексту"?
что происходит, когда вы пытаетесь это сделать?
У меня нет времени, чтобы попробовать это, пока нет. Но я всегда стараюсь понять команду, прежде чем ее использовать. И здесь я не понимаю, что произойдет с 2-значным часом, например, 13 или 23…
Во-первых, это плохо:
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 или через несколько (милли) секунд. И это не проблема в тестах, сделанных здесь. Но у вас есть точка зрения здесь. Желательно получать часы и минуты одновременно. Я это реализую. Спасибо.
В числовом контексте строки, начинающиеся с нуля, считаются восьмеричными. Следовательно, 08
ошибочно.
Однако я бы не стала заниматься арифметикой, чтобы проверить ваше состояние. Вместо этого я бы сделал что-то вроде
if [[ $(date +%HM) == ?[02468]00 ]]
then
....
fi
Это то, что @m-nejat-aydin ответил перед вами. Это похоже на регулярное выражение, но для bash? Не могли бы вы объяснить, как это работает?
Это не регулярное выражение, а глобальный шаблон. В [[ E1 == E2 ]]
E2 рассматривается как шаблон глобуса, а E1 сопоставляется с ним. Синтаксис подстановки объясняется в разделе «Расширение пути» на странице руководства bash. Будьте осторожны: если E2 заключен в кавычки, сопоставление с образцом отключено. Вы также можете использовать сопоставление регулярных выражений (bash использует расширенное регулярное выражение POSIX). В этом случае используется синтаксис [[ E1 =~ E2 ]]
.
Спасибо за вашу помощь. Сегодня я кое-чему научился :) Могу ли я отправить весь сценарий на проверку?