Wat is de beste manier om een do-while-lus in Bash te emuleren?
Ik zou de voorwaarde kunnen controleren voordat ik de while
-lus betreed, en dan doorgaan met het opnieuw controleren van de voorwaarde in de lus, maar dat is gedupliceerde code. Is er een schonere manier?
Pseudocode van mijn script:
while [ current_time <= $cutoff ]; do
check_if_file_present
#do other stuff
done
Dit voert check_if_file_present
niet uit als het wordt gestart na de $cutoff
-tijd, en een do-while zou dat wel doen.
Antwoord 1, autoriteit 100%
Twee eenvoudige oplossingen:
-
Voer uw code één keer uit vóór de while-lus
actions() { check_if_file_present # Do other stuff } actions #1st execution while [ current_time <= $cutoff ]; do actions # Loop execution done
-
Of:
while : ; do actions [[ current_time <= $cutoff ]] || break done
Antwoord 2, autoriteit 60%
Plaats de hoofdtekst van je lus na de while
en vóór de test. De eigenlijke hoofdtekst van de while
-lus zou een no-op moeten zijn.
while
check_if_file_present
#do other stuff
(( current_time <= cutoff ))
do
:
done
In plaats van de dubbele punt kunt u continue
gebruiken als u dat beter leesbaar vindt. Je kunt ook een commando invoegen dat alleen tusseniteraties uitvoert (niet voor de eerste of na de laatste), zoals echo "Retrying in five seconds"; sleep 5
. Of print scheidingstekens tussen waarden:
i=1; while printf '%d' "$((i++))"; (( i <= 4)); do printf ','; done; printf '\n'
Ik heb de test gewijzigd om dubbele haakjes te gebruiken, omdat je gehele getallen lijkt te vergelijken. Tussen dubbele vierkante haken zijn vergelijkingsoperatoren zoals <=
lexicaal en geven ze het verkeerde resultaat bij het vergelijken van bijvoorbeeld 2 en 10. Die operatoren werken niet tussen enkele vierkante haken.
Antwoord 3, autoriteit 3%
Deze implementatie:
- Heeft geen codeduplicatie
- Vereist geen extra functies()
- Hangt niet af van de geretourneerde waarde van code in de “while”-sectie van de lus:
do=true
while $do || conditions; do
do=false
# your code ...
done
Het werkt ook met een leeslus, waarbij de eerste lezing wordt overgeslagen:
do=true
while $do || read foo; do
do=false
# your code ...
echo $foo
done
Antwoord 4, autoriteit 2%
We kunnen een do-while-lus in Bash emuleren met while [[condition]]; do true; done
als volgt:
while [[ current_time <= $cutoff ]]
check_if_file_present
#do other stuff
do true; done
Bijvoorbeeld. Hier is mijn implementatie voor het verkrijgen van een ssh-verbindingin bash-script:
#!/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
Het geeft de uitvoer in de volgorde zoals hieronder:
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"