경과 시간을 계산하는 Bash 스크립트


118

내 명령 실행에 경과 된 시간을 계산하기 위해 bash에서 스크립트를 작성 중입니다. 다음을 고려하십시오.

STARTTIME=$(date +%s)
#command block that takes time to complete...
#........
ENDTIME=$(date +%s)
echo "It takes $($ENDTIME - $STARTTIME) seconds to complete this task..."

내 논리가 정확하다고 생각하지만 다음과 같은 인쇄물로 끝납니다.

"이 작업을 완료하는 데 몇 초가 걸립니다 ..."

내 문자열 평가에 문제가 있습니까?

나는 bash 변수가 형식화되지 않았다고 생각한다. 그럼에도 불구하고 bash에 "string to integer"메소드가 있다면 좋아할 것이다.

답변:


83

어느 $(())또는 $[]산술 연산의 결과를 계산하기 위해 작동한다. 당신은 사용하고 있습니다$() 은 단순히 문자열을 가져 와서 명령으로 평가하는 것을 사용하고 있습니다. 약간 미묘한 차이입니다. 도움이 되었기를 바랍니다.

이 답변에 대한 주석에서 tink가 지적했듯이 $[]더 이상 사용되지 않으며 $(())선호되어야합니다.


7
bash 4.x 맨 페이지에 $ [] 가 더 이상 사용되지 않으며 향후 버전에서 제거 될 것이라고 명시되어 있으므로이 두 가지를 교체 할 수 있습니다.
2013-06-04

2
고마워요.
OmnipotentEntity 2013 년

157

내부 변수 "$ SECONDS"를 사용하는 것이 매우 깔끔합니다.

SECONDS=0 ; sleep 10 ; echo $SECONDS


10
만 성공 =)
론 Kaut

1
성공이 필요합니다. 당신의 것을 사용하십시오
Gromish 2016 년

3
$SECONDS실제로 / bin / bash에서 작동합니다. Debian 및 Ubuntu의 기본 셸인 / bin / dash에서는 작동하지 않습니다.
Cameron Taggart

2
이 솔루션의 단점은 전체 초만 측정한다는 것입니다. 즉, 1 초 미만의 정밀도가 필요한 경우 사용할 수 없습니다.
Czechnology

@Czechnology 예, sleep 0.5위에서 사용 하면 결과는 때때로 0, 때로는 1입니다 (적어도 Bash 5.0.3에 의해).
jarno

52

에서 번호를 ENDTIME명령으로 실행하려고합니다 . 또한와 같은 오류가 표시되어야합니다 1370306857: command not found. 대신 산술 확장을 사용하십시오 .

echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete this task..."

명령을 별도의 스크립트에 저장하고 commands.shtime 명령을 사용할 수도 있습니다.

time commands.sh

28

time적절한 형식 문자열과 함께 여기에서 Bash의 키워드를 사용할 수 있습니다.

TIMEFORMAT='It takes %R seconds to complete this task...'
time {
    #command block that takes time to complete...
    #........
 }

다음은 참조가 말하는 내용입니다TIMEFORMAT .

이 매개 변수의 값은 time 예약어로 시작하는 파이프 라인의 타이밍 정보를 표시하는 방법을 지정하는 형식 문자열로 사용 됩니다. ' %'문자는 시간 값 또는 기타 정보로 확장되는 이스케이프 시퀀스를 도입합니다. 이스케이프 시퀀스와 그 의미는 다음과 같습니다. 중괄호는 선택적 부분을 나타냅니다.

%%

    A literal ‘%’.
%[p][l]R

    The elapsed time in seconds.
%[p][l]U

    The number of CPU seconds spent in user mode.
%[p][l]S

    The number of CPU seconds spent in system mode.
%P

    The CPU percentage, computed as (%U + %S) / %R. 

선택적 p 는 소수점 뒤의 소수 자릿수 인 정밀도를 지정하는 숫자입니다. 값이 0이면 소수점이나 분수가 출력되지 않습니다. 소수점 이하 세 자리까지 지정할 수 있습니다. 3보다 큰 p의 값은 3으로 변경됩니다. p 를 지정하지 않으면 값 3이 사용됩니다.

선택 사항 lMMmSS.FFs 형식의 분을 포함하여 더 긴 형식을 지정합니다 . p 값은 분수가 포함되는지 여부를 결정합니다.

이 변수가 설정되어 있지 않으면 Bash는 값이있는 것처럼 작동합니다.

$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'

값이 null이면 타이밍 정보가 표시되지 않습니다. 형식 문자열이 표시 될 때 후행 개행이 추가됩니다.


10

더 큰 숫자의 경우 더 읽기 쉬운 형식으로 인쇄 할 수 있습니다. 아래 예제는 다른 예제와 동일하지만 "인간"형식으로도 인쇄합니다.

secs_to_human() {
    if [[ -z ${1} || ${1} -lt 60 ]] ;then
        min=0 ; secs="${1}"
    else
        time_mins=$(echo "scale=2; ${1}/60" | bc)
        min=$(echo ${time_mins} | cut -d'.' -f1)
        secs="0.$(echo ${time_mins} | cut -d'.' -f2)"
        secs=$(echo ${secs}*60|bc|awk '{print int($1+0.5)}')
    fi
    echo "Time Elapsed : ${min} minutes and ${secs} seconds."
}

간단한 테스트 :

secs_to_human "300"
secs_to_human "305"
secs_to_human "59"
secs_to_human "60"
secs_to_human "660"
secs_to_human "3000"

산출:

Time Elapsed : 5 minutes and 0 seconds.
Time Elapsed : 5 minutes and 5 seconds.
Time Elapsed : 0 minutes and 59 seconds.
Time Elapsed : 1 minutes and 0 seconds.
Time Elapsed : 11 minutes and 0 seconds.
Time Elapsed : 50 minutes and 0 seconds.

다른 게시물에 설명 된대로 스크립트에서 사용하려면 (시작 지점을 캡처 한 다음 종료 시간과 함께 함수를 호출합니다.

start=$(date +%s)
# << performs some task here >>
secs_to_human "$(($(date +%s) - ${start}))"

9

다음 코드를 시도하십시오.

start=$(date +'%s') && sleep 5 && echo "It took $(($(date +'%s') - $start)) seconds"

5

이것은 Mike Q의 기능에 대한 한 줄짜리 대안입니다.

secs_to_human() {
    echo "$(( ${1} / 3600 ))h $(( (${1} / 60) % 60 ))m $(( ${1} % 60 ))s"
}

좋은! 나는 일반적으로 내 bash 코드에 대해 매우 장황합니다.
Mike Q

이것을 SECONDSLon Kaut의 답변 과 결합 하고 $ / $ {}가 산술 ​​변수에 필요하지 않다는 점을 염두에두면 코드가 너무 짧아서 인라인으로도 사용할 수 있습니다.echo "$((SECONDS/3600))h $(((SECONDS/60)%60))m $((SECONDS%60))s"
ssc

2

경과 된 초 옵션과 함께 시간을 사용해보십시오.

/usr/bin/time -f%e sleep 1 bash에서.

또는 \time -f%e sleep 1대화 형 bash에서.

시간 매뉴얼 페이지를 참조하십시오.

bash 쉘 사용자는 쉘 내장 변형이 아닌 외부 시간 명령을 실행하기 위해 명시 적 경로를 사용해야합니다. time이 / usr / bin에 설치된 시스템에서 첫 번째 예제는 / ​​usr / bin / time wc / etc / hosts가됩니다.

FORMATTING THE OUTPUT
...
    %      A literal '%'.
    e      Elapsed  real  (wall  clock) time used by the process, in
                 seconds.

1
/bin/time여기서 작동하지 않습니다. OP는 블록을 언급합니다 . time여기 에 키워드가 정말 필요합니다 .
gniourf_gniourf

-3
start=$(date +%Y%m%d%H%M%S);
for x in {1..5};
do echo $x;
sleep 1; done;
end=$(date +%Y%m%d%H%M%S);
elapsed=$(($end-$start));
ftime=$(for((i=1;i<=$((${#end}-${#elapsed}));i++));
        do echo -n "-";
        done;
        echo ${elapsed});
echo -e "Start  : ${start}\nStop   : ${end}\nElapsed: ${ftime}"

Start  : 20171108005304
Stop   : 20171108005310
Elapsed: -------------6

-3
    #!/bin/bash

    time_elapsed(){
    appstop=$1; appstart=$2

    ss_strt=${appstart:12:2} ;ss_stop=${appstop:12:2}
    mm_strt=${appstart:10:2} ;mm_stop=${appstop:10:2}
     hh_strt=${appstart:8:2} ; hh_stop=${appstop:8:2}
     dd_strt=${appstart:6:2} ; dd_stop=${appstop:6:2}
     mh_strt=${appstart:4:2} ; mh_stop=${appstop:4:2}
     yy_strt=${appstart:0:4} ; yy_stop=${appstop:0:4}

    if [ "${ss_stop}" -lt "${ss_strt}" ]; then ss_stop=$((ss_stop+60)); mm_stop=$((mm_stop-1)); fi
    if [ "${mm_stop}" -lt "0" ]; then mm_stop=$((mm_stop+60)); hh_stop=$((hh_stop-1)); fi
    if [ "${mm_stop}" -lt "${mm_strt}" ]; then mm_stop=$((mm_stop+60)); hh_stop=$((hh_stop-1)); fi
    if [ "${hh_stop}" -lt "0" ]; then hh_stop=$((hh_stop+24)); dd_stop=$((dd_stop-1)); fi
    if [ "${hh_stop}" -lt "${hh_strt}" ]; then hh_stop=$((hh_stop+24)); dd_stop=$((dd_stop-1)); fi

    if [ "${dd_stop}" -lt "0" ]; then dd_stop=$((dd_stop+$(mh_days $mh_stop $yy_stop))); mh_stop=$((mh_stop-1)); fi
    if [ "${dd_stop}" -lt "${dd_strt}" ]; then dd_stop=$((dd_stop+$(mh_days $mh_stop $yy_stop))); mh_stop=$((mh_stop-1)); fi

    if [ "${mh_stop}" -lt "0" ]; then mh_stop=$((mh_stop+12)); yy_stop=$((yy_stop-1)); fi
    if [ "${mh_stop}" -lt "${mh_strt}" ]; then mh_stop=$((mh_stop+12)); yy_stop=$((yy_stop-1)); fi

    ss_espd=$((10#${ss_stop}-10#${ss_strt})); if [ "${#ss_espd}" -le "1" ]; then ss_espd=$(for((i=1;i<=$((${#ss_stop}-${#ss_espd}));i++)); do echo -n "0"; done; echo ${ss_espd}); fi
    mm_espd=$((10#${mm_stop}-10#${mm_strt})); if [ "${#mm_espd}" -le "1" ]; then mm_espd=$(for((i=1;i<=$((${#mm_stop}-${#mm_espd}));i++)); do echo -n "0"; done; echo ${mm_espd}); fi
    hh_espd=$((10#${hh_stop}-10#${hh_strt})); if [ "${#hh_espd}" -le "1" ]; then hh_espd=$(for((i=1;i<=$((${#hh_stop}-${#hh_espd}));i++)); do echo -n "0"; done; echo ${hh_espd}); fi
    dd_espd=$((10#${dd_stop}-10#${dd_strt})); if [ "${#dd_espd}" -le "1" ]; then dd_espd=$(for((i=1;i<=$((${#dd_stop}-${#dd_espd}));i++)); do echo -n "0"; done; echo ${dd_espd}); fi
    mh_espd=$((10#${mh_stop}-10#${mh_strt})); if [ "${#mh_espd}" -le "1" ]; then mh_espd=$(for((i=1;i<=$((${#mh_stop}-${#mh_espd}));i++)); do echo -n "0"; done; echo ${mh_espd}); fi
    yy_espd=$((10#${yy_stop}-10#${yy_strt})); if [ "${#yy_espd}" -le "1" ]; then yy_espd=$(for((i=1;i<=$((${#yy_stop}-${#yy_espd}));i++)); do echo -n "0"; done; echo ${yy_espd}); fi

    echo -e "${yy_espd}-${mh_espd}-${dd_espd} ${hh_espd}:${mm_espd}:${ss_espd}"
    #return $(echo -e "${yy_espd}-${mh_espd}-${dd_espd} ${hh_espd}:${mm_espd}:${ss_espd}")
    }

    mh_days(){
    mh_stop=$1; yy_stop=$2; #also checks if it's leap year or not

    case $mh_stop in
     [1,3,5,7,8,10,12]) mh_stop=31
     ;;
     2) (( !(yy_stop % 4) && (yy_stop % 100 || !(yy_stop % 400) ) )) && mh_stop=29 || mh_stop=28
     ;;
     [4,6,9,11]) mh_stop=30
     ;;
    esac

    return ${mh_stop}
    }

    appstart=$(date +%Y%m%d%H%M%S); read -p "Wait some time, then press nay-key..." key; appstop=$(date +%Y%m%d%H%M%S); elapsed=$(time_elapsed $appstop $appstart); echo -e "Start...: ${appstart:0:4}-${appstart:4:2}-${appstart:6:2} ${appstart:8:2}:${appstart:10:2}:${appstart:12:2}\nStop....: ${appstop:0:4}-${appstop:4:2}-${appstop:6:2} ${appstop:8:2}:${appstop:10:2}:${appstop:12:2}\n$(printf '%0.1s' "="{1..30})\nElapsed.: ${elapsed}"

    exit 0


-------------------------------------------- return
Wait some time, then press nay-key...
Start...: 2017-11-09 03:22:17
Stop....: 2017-11-09 03:22:18
==============================
Elapsed.: 0000-00-00 00:00:01
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.