Een do-while-lus emuleren in Bash

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_presentniet uit als het wordt gestart na de $cutoff-tijd, en een do-while zou dat wel doen.


Antwoord 1, autoriteit 100%

Twee eenvoudige oplossingen:

  1. 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
    
  2. Of:

    while : ; do
        actions
        [[ current_time <= $cutoff ]] || break
    done
    

Antwoord 2, autoriteit 60%

Plaats de hoofdtekst van je lus na de whileen 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 continuegebruiken 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; doneals 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"

Other episodes