상태에서 큰 타격

상태에서 큰 타격

잠시 기다렸다가 디렉터리에 여러 파일이 있는지 확인하는 두 가지 조건이 있습니다. 이러한 조건 중 하나가 true이면 루프를 실행해야 하므로 정상적인 OR 논리문입니다.

예상되는 동작은 시간이 경과하거나 디렉터리에 파일이 두 개 이상 있으면 루프가 종료됨을 의미합니다. 하나 이상의 문서가 아직 대기 중입니다. 누군가 내 while 루프가 예상대로 작동하지 않는 이유를 설명할 수 있습니까?

i=1; while [ $i -le 10 ] || [ $( ls /opt/hosts/ | wc -l ) -lt 2 ]; do sleep 3 $(( i++ )); done

불행히도 한 줄 명령이 필요합니다. 내 명령이 왜 OR이 예상대로 작동하지 않는 무한 루프인지 알고 싶습니다. (첫 번째 조건을 3으로 변경했습니다.)

+ echo host_name 
+ i=1 
+ '[' 1 -le 2 ']' 
+ sleep 1 1 
+ '[' 2 -le 2 ']' 
+ sleep 1 2 
+ '[' 3 -le 2 ']' 
++ ls /opt/hosts/ 
++ wc -l 
+ '[' 1 -lt 2 ']' 
+ sleep 1 3 
+ '[' 4 -le 2 ']' 
++ ls /opt/hosts/ 
++ wc -l 
+ '[' 1 -lt 2 ']' 
+ sleep 1 4 
+ '[' 5 -le 2 ']' 
++ ls /opt/hosts/ 
++ wc -l 
+ '[' 1 -lt 2 ']' 
+ sleep 1 5 ```

답변1

  • sleep두 개의 매개변수를 제공 3하고 $(( i++ )). GNU 도구의 경우 이는 반복할 때마다 루프가 휴면 상태에 있는 시간(초)이 증가함을 의미합니다. GNU가 아닌 시스템에서는 sleep.

  • 루프는 항상 실행됩니다적어도테스트 작성 방법에 따라 10번. 테스트에 " $i10보다 작거나 같은 반복"이라고 표시됩니다. 10에 도달 하면 $i테스트의 다른 부분이 적용됩니다. 여기서는 OR 대신 논리적 AND 테스트를 수행할 수 있습니다.

  • ls | wc -l디렉토리의 파일 수를 계산하는 데 사용해서는 안됩니다 . 일부(병리적이긴 하지만) 경우 이는 잘못된 결과를 초래할 수 있습니다.

대신에:

i=1
while [ "$i" -ne 10 ]; do
    set -- /opt/hosts/*
    if [ "$#" -ge 2 ]; then
        break
    fi

    sleep 3         # or, to sleep longer and longer: sleep "$(( 3 + i ))"
    i=$(( i + 1 ))
done

이는 i각 반복마다 적절하게 증가하며 디렉터리의 이름 수를 계산하는 보다 안전한 방법을 사용합니다 /opt/hosts(디렉토리에서 glob을 확장 *하고 확장된 이름 수를 계산하여). 이름 수가 2개 이상이거나 $i값이 10에 도달할 때마다 루프가 종료됩니다.

루프 후 $i10이면 파일이 구체화되지 않은 것입니다.

위치 인수( 명령에 의해 재정의됨 set)를 유지해야 하는 경우 를 사용하는 대신 glob을 배열로 확장한 names=( /opt/hosts/* )다음 "${#names[@]}"해당 배열의 길이를 가져옵니다 "$#".

당신은 또한 쓸 수 있습니다

i=1
while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] )
do
    sleep 3
    i=$(( i + 1 ))
done

set이는 서브셸에서 실행하는 기존 위치 인수를 삭제하지 않습니다 . 그것은 또한 당신이 직접 시도해 본 유형에 더 가깝습니다.


"한 줄"로:

i=1; while [ "$i" -ne 10 ]; do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; i=$(( i + 1 )); done

또는 "산술 for루프"를 사용하십시오 bash.

for (( i=1; i<=10; i++ )); do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; done

또는 구분선 위의 마지막 코드 부분을 사용하세요.

i=1; while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] ); do sleep 3; i=$(( i + 1 )); done

관련 정보