Bash "while" 루프가 종료되면 조건부 함수의 종료 코드가 필요합니다.

Bash "while" 루프가 종료되면 조건부 함수의 종료 코드가 필요합니다.

whileBash 루프의 "조건" 섹션에서 반복적으로 호출하는 함수의 종료 코드를 얻으려고 합니다 .

while <function>; do 
    <stuff> 
done 

오류로 인해 이 루프가 종료될 때 필요한 종료 코드입니다 <function>. 그것을 얻는 방법에 대한 아이디어가 있습니까?

답변1

조건의 종료 값을 캡처하여 앞으로 전파할 수 있습니다.

while rmdir FOO; ss=$?; [[ $ss -eq 0 ]]
do
    echo in loop
done
echo "out of loop with ?=$? but ss=$ss"

산출

rmdir: failed to remove 'FOO': No such file or directory
out of loop with ?=0 but ss=1

이 경우 종료 상태는 rmdir FOO변수에 캡처되었으며 ss입니다 1. ( rmdir FOO로 바꿔보세요 ( exit 4 ). 가 표시됩니다 ss=4.)

어떻게 작동하나요? 구문은 실제로 while list-1; do list-2; done더 일반적인 기대가 아니라는 점을 명심하십시오 while command; do list; done. 세미콜론으로 구분된 일련의 명령일 수 있으며 list-1설명서에는 "whilelist-2이 명령은 목록의 마지막 명령이 종료 상태 0을 반환하는 한 list-1목록을 계속 실행합니다 ."

혼란스러워 보이는 while조건을 표현하는 또 다른 방법 으로 표현식 내부에 변수를 할당한 (( ... ))후 그 결과를 사용할 수 있습니다. 이는 읽기가 더 어렵지만 보다 간결한 할당 및 테스트 구조를 제공합니다.

while rmdir FOO; ((! (ss=$?)))
do
    echo in loop
done
echo "out of loop with ?=$? but ss=$ss"

또는 를 사용할 수 있습니다 while rmdir FOO; ! (( ss=$? )). 이는 ((1))의 산술 평가가 1이고 일반적으로 true와 연관되어 해당 평가에 대한 종료 코드가 0(성공)이기 때문에 작동합니다. 반면에 ((0))의 산술 평가는 0이며 이는 일반적으로 false와 연관되므로 이 계산의 종료 코드는 1(실패)입니다. 두 평가가 모두 "성공"한 후에 혼란스러워 보일 수 있지만 bash의 성공/실패 종료 코드와 일치하는 true/false를 나타내는 산술 표현식의 값을 만들고 , 등 ((.))의 조건식을 기반으로 하는지 여부에 관계없이 만드는 것은 해킹입니다. 종료 코드나 산술 값에서는 모두 잘 작동합니다.if ...; then ...; fiwhile ...; do ...; done

답변2

이를 달성하는 한 가지 방법은 테스트를 위임하는 대신 명시적으로 만드는 것입니다 while. 따라서 다음을 수행해야 합니다.

err=0
while true
do
    <function>
    (( (err=$?) > 0 )) && break
    <stuff>
done
echo "$err"

(선험적 무한) 루프의 시작 부분에서 조건부 명령을 "수동으로" 실행하고 종료 코드를 저장하고 확인한 후 0이 아닌 경우(실패를 나타냄) 루프를 종료합니다. 0일 때만 "실제" 루프 코드를 실행합니다.

@roaima가 지적했듯이 (( ... ))산술 테스트 구성 내에서 변수 할당을 수행할 수 있기 때문에 구문을 "압축"할 수 있습니다.

답변3

함수의 종료 코드 결과로 변수를 설정하는 래퍼 함수를 ​​만듭니다. 예:

e=0

# file does not exist
foo() { 
  rm xyz
}

baz() { 
  foo
  e=$?
  [[ $e -ne 0 ]] && return 1
  return 0
}

# create a file
touch xyz
while baz; do
  # first loop succeeds, the file exists
  # second loop exits with error, file doesn't exists
  echo in loop
done
in loop
rm: cannot remove 'xyz': No such file or directory
# then
$ echo $e
1

답변4

를 사용하면 익명 함수에서 사용할 zsh수 있습니다 .return

() while ((1)) {
  <function> || return
  <stuff>
}
print $?

Bourne과 유사한 쉘의 경우 언제든지 명명된 함수를 사용할 수 있습니다.

repeat_until_fail()
  while true; do
    <function> || return
    <stuff>
  done

repeat_until_fail
echo "$?"

관련 정보