Bash에서 do-while 루프 에뮬레이션


137

Bash에서 do-while 루프를 에뮬레이트하는 가장 좋은 방법은 무엇입니까?

while루프에 들어가기 전에 조건을 확인한 다음 루프 에서 조건 을 계속 다시 확인할 수 있지만 코드가 중복됩니다. 더 깨끗한 방법이 있습니까?

내 스크립트의 의사 코드 :

while [ current_time <= $cutoff ]; do
    check_if_file_present
    #do other stuff
done

시간이 check_if_file_present지나면 실행되지 않으며 $cutoff, 그 동안에는 수행되지 않습니다 .


until스위치 를 찾고 있습니까?
Michael Gardner

2
@MichaelGardner until는 루프 본문을 실행하기 전에 조건을 평가합니다
Alex

2
아, 나는 당신의 Quandry를 오해했습니다.
마이클 가드너

답변:


216

두 가지 간단한 솔루션 :

  1. while 루프 전에 코드를 한 번 실행

    actions() {
       check_if_file_present
       # Do other stuff
    }
    
    actions #1st execution
    while [ current_time <= $cutoff ]; do
       actions # Loop execution
    done
  2. 또는:

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

9
:내장에 해당하는 내장입니다 true. 그들은 "아무것도하지 않습니다".
loxaxs

2
@loxaxs는 zsh에는 적용되지만 Bash에는 적용되지 않습니다. 내장 된 true반면 실제 프로그램 :입니다. 전자는 단순히로 종료 0(와 false함께 1후자는 절대적으로 아무것도하지 않는다). 로 확인할 수 있습니다 which true.
Fleshgrinder

Bash :대신 @Fleshgrinder 를 계속 사용할 수 true있습니다. 로 사용해보십시오 while :; do echo 1; done.
Alexej Magura

2
trueBash에 내장 된 것이 아닌 다른 말은하지 마십시오 . 일반적으로의 프로그램입니다 /bin.
Fleshgrinder

type truebash에서 (bash 3.2까지)는을 반환합니다 true is a shell builtin. /bin/true프로그램 이라는 것은 사실입니다 . 사실에 대해 진실 true이 아닌 것은 그것이 내장이 아니라는 것입니다. (tl; dr : true는 bash 내장 및 프로그램입니다)
PJ Eby

152

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을 비교할 때 잘못된 결과를 제공합니다. 이러한 연산자는 단일 대괄호 안에서 작동하지 않습니다.


한 줄과 동일 while { check_if_file_present; ((current_time<=cutoff)); }; do :; done합니까? 즉, while조건 내부의 명령 은 예를 들어 세미콜론으로 효과적으로 분리되지 않고 &&그룹화되어 {}있습니까?
Ruslan

@Ruslan : 중괄호는 필요하지 않습니다. 다음을 사용하여 이중 괄호 안에 시험에 아무것도 연결하지 않아야 &&또는 ||그 효과적으로 테스트하는 것이 제어의 그 부분을 만드는 것이므로 while. 명령 줄 에서이 구문을 사용하지 않는 한 의도를 읽을 수 없으므로 스크립트에서 하나의 라이너로 사용하지는 않습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

예, 나는 그것을 하나의 라이너로 사용하려고하지 않았습니다. 테스트의 명령이 어떻게 연결되어 있는지 명확히하기 위해서입니다. 0이 아닌 값을 반환하는 첫 번째 명령이 전체 조건을 거짓으로 만들 수 있다고 걱정했습니다.
Ruslan

3
@ruslan : 아니요, 마지막 반환 값입니다. while false; false; false; true; do echo here; break; doneoutputs "here"
추후 공지가있을 때까지 일시 중지되었습니다.

@ thatotherguy : 능력 사이의 것은 아주 멋지다! 문자열을 사용하여 구분자를 삽입 할 수도 있습니다. 감사!
추후 공지가있을 때까지 일시 중지되었습니다.

2

Bash에서 do-while 루프를 다음과 while [[condition]]; do true; done같이 에뮬레이트 할 수 있습니다 .

while [[ current_time <= $cutoff ]]
    check_if_file_present
    #do other stuff
do true; done

예를 들어. bash 스크립트에서 ssh 연결 을 얻는 구현은 다음과 같습니다 .

#!/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' (git@github.com: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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.