bash 스크립트: 고정된 절전 시간이 while 루프에 누적됩니다.

bash 스크립트: 고정된 절전 시간이 while 루프에 누적됩니다.

저는 bash 스크립팅을 처음 접하고 몇 가지 예제 스크립트로 시작합니다.

하나는:

#!/bin/bash
SECONDS=5
i=1

while true
do
        echo "`date`: Loop $i"
        i=$(( $i+1 ))
        sleep $SECONDS
done

그 결과는 다음과 같습니다.

Sunday 10 May  15:08:20 AEST 2020: Loop 1
Sunday 10 May  15:08:25 AEST 2020: Loop 2
Sunday 10 May  15:08:35 AEST 2020: Loop 3
Sunday 10 May  15:08:55 AEST 2020: Loop 4

...이것은 내가 기대하거나 스크립트에서 수행하기를 원하는 것이 아닙니다.

루프를 통과할 때마다 초 수가 두 배로 늘어나는 이유는 무엇입니까?

bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

답변1

SECONDSbash의 내부 변수이기 때문입니다 . 쉘이 실행된 시간을 저장합니다.

에서 man bash:

SECONDS
이 매개변수가 참조될 때마다 쉘이 호출된 이후의 시간(초)이 반환됩니다. 값이 SECONDS에 할당되면 후속 참조에서 반환되는 값은 할당 이후의 초 수에 할당된 값을 더한 값입니다.

따라서 스크립트는 다음과 같이 작동합니다.

  1. 처음 사용되면 값 5를 입력으로 받아들이고 초기 값은 5입니다.
  2. 그런 다음 5초의 수면이 있으며, 수면이 반환되면 SECONDS의 값은 초기 값의 5초 + 5초의 수면 = 10초가 됩니다.
  3. 그런 다음 10초(현재 값 SECONDS)에 이전 10초의 누적 시간인 20을 더해 수면을 취합니다.
  4. 20초 동안 수면을 반복하고 이전 값인 20을 40에 추가합니다.
  5. 등.

답변2

이 구성에는 2차 문제가 있습니다. 루프의 처리에 많은 시간이 걸리는 경우(예: 1.4초) 루프는 6.4초마다 반복됩니다.

이것이 중요한 경우 대신 사이클 수를 계산할 수 있습니다.

#!/bin/bash

Expired=$(( SECONDS + 23 ))
Tick=5
Iter=1

while (( SECONDS < Expired )); do
    echo "$(date '+%T.%N'): Loop $Iter"
    sleep 1.4  #.. Simulate work.
    echo "$(date '+%T.%N'): Idle"
    sleep $(( Iter++ * Tick - SECONDS ))
done                    

사이클 시간은 초 단위의 정수 정밀도 내에서 안정적입니다.

Expired를 초기화하기 위해 더 복잡한 산술을 수행할 수 있습니다(예를 들어, 두 개의 날짜 명령을 사용하여 자정까지의 시간(초)을 찾습니다).

관련 정보