
저는 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
SECONDS
bash의 내부 변수이기 때문입니다 . 쉘이 실행된 시간을 저장합니다.
에서 man bash
:
SECONDS
이 매개변수가 참조될 때마다 쉘이 호출된 이후의 시간(초)이 반환됩니다. 값이 SECONDS에 할당되면 후속 참조에서 반환되는 값은 할당 이후의 초 수에 할당된 값을 더한 값입니다.
따라서 스크립트는 다음과 같이 작동합니다.
- 처음 사용되면 값 5를 입력으로 받아들이고 초기 값은 5입니다.
- 그런 다음 5초의 수면이 있으며, 수면이 반환되면 SECONDS의 값은 초기 값의 5초 + 5초의 수면 = 10초가 됩니다.
- 그런 다음 10초(현재 값 SECONDS)에 이전 10초의 누적 시간인 20을 더해 수면을 취합니다.
- 20초 동안 수면을 반복하고 이전 값인 20을 40에 추가합니다.
- 등.
답변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를 초기화하기 위해 더 복잡한 산술을 수행할 수 있습니다(예를 들어, 두 개의 날짜 명령을 사용하여 자정까지의 시간(초)을 찾습니다).