Эмуляция цикла do-while в Bash
Каков наилучший способ эмуляции цикла do-while в Bash?
Я могу проверить условие перед входом в цикл while
, а затем продолжить повторную проверку условия в цикле, но этот дублированный код. Есть ли более чистый способ?
Псевдокод моего script:
while [ current_time <= $cutoff ]; do
check_if_file_present
#do other stuff
done
Это не выполняется check_if_file_present
, если оно запущено после $cutoff
времени, а do-while будет.
Ответы
Ответ 1
Два простых решения:
-
Выполняйте свой код один раз перед циклом while
actions() {
check_if_file_present
# Do other stuff
}
actions #1st execution
while [ current_time <= $cutoff ]; do
actions # Loop execution
done
-
Или:
while : ; do
actions
[[ current_time <= $cutoff ]] || break
done
Ответ 2
Поместите тело вашей циклы после while
и перед тестом. Фактическое тело цикла while
должно быть неактивным.
while
check_if_file_present
#do other stuff
(( current_time <= cutoff ))
do
:
done
Вместо двоеточия вы можете использовать continue
, если вы найдете это более читабельным. Вы также можете вставить команду, которая будет выполняться только между итерациями (не до первой или после последней), например echo "Retrying in five seconds"; sleep 5
. Или распечатайте разделители между значениями:
i=1; while printf '%d' "$((i++))"; (( i <= 4)); do printf ','; done; printf '\n'
Я изменил тест, чтобы использовать двойные скобки, так как вы, кажется, сравниваете целые числа. Внутри двойных квадратных скобок операторы сравнения, такие как <=
, являются лексическими и будут давать неверный результат, например, при сравнении 2 и 10. Эти операторы не работают внутри одинарных квадратных скобок.
Ответ 3
Вместо двоеточия вы можете использовать продолжить, если вы найдете, что более читабельным
Этот метод имитирует способ выполнения циклов Do-While, который я искал - чтобы иметь тест состояния после действий. Я также обнаружил, что я могу поместить приращение индекса (если необходимо) после оператора do вместо оператора continue.
while
check_if_file_present
#do other stuff
(( current_time <= cutoff ))
do
(( index++ ));
done
Ответ 4
Мы можем эмулировать цикл выполнения в Bash с помощью while [[condition]]; do true; done
следующим образом:
while [[ current_time <= $cutoff ]]
check_if_file_present
#do other stuff
do true; done
Для примера. Вот моя реализация получения ssh-соединения в bash-скрипте:
#!/bin/bash
while [[ $STATUS != 0 ]]
ssh-add -l &>/dev/null; STATUS="$?"
if [[ $STATUS == 127 ]]; then echo "ssh not instaled" && exit 0;
elif [[ $STATUS == 2 ]]; then echo "running ssh-agent.." && eval 'ssh-agent' > /dev/null;
elif [[ $STATUS == 1 ]]; then echo "get session identity.." && expect $HOME/agent &> /dev/null;
else ssh-add -l && git submodule update --init --recursive --remote --merge && return 0; fi
do true; done
Он выдаст выходные данные в следующей последовательности:
Step #0 - "gcloud": intalling expect..
Step #0 - "gcloud": running ssh-agent..
Step #0 - "gcloud": get session identity..
Step #0 - "gcloud": 4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /builder/home/.ssh/id_rsa (RSA)
Step #0 - "gcloud": Submodule '.google/cloud/compute/home/chetabahana/.docker/compose' ([email protected]:chetabahana/compose) registered for path '.google/cloud/compute/home/chetabahana/.docker/compose'
Step #0 - "gcloud": Cloning into '/workspace/.io/.google/cloud/compute/home/chetabahana/.docker/compose'...
Step #0 - "gcloud": Warning: Permanently added the RSA host key for IP address 'XXX.XX.XXX.XXX' to the list of known hosts.
Step #0 - "gcloud": Submodule path '.google/cloud/compute/home/chetabahana/.docker/compose': checked out '24a28a7a306a671bbc430aa27b83c09cc5f1c62d'
Finished Step #0 - "gcloud"