Script Bash per calcolare il tempo trascorso


118

Sto scrivendo uno script in bash per calcolare il tempo trascorso per l'esecuzione dei miei comandi, considera:

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

Immagino che la mia logica sia corretta, ma alla fine ho la seguente stampa:

"Ci vogliono pochi secondi per completare questa operazione ..."

Qualcosa non va con la mia valutazione delle stringhe?

Credo che le variabili bash non siano tipizzate, mi piacerebbe se ci fosse un metodo "string to integer" in bash comunque.

Risposte:


83

Sia $(())o $[]lavorerà per calcolare il risultato di un'operazione aritmetica. Stai usando $()che sta semplicemente prendendo la stringa e valutandola come un comando. È una distinzione un po 'sottile. Spero che questo ti aiuti.

Come Tink ha sottolineato nei commenti a questa risposta, $[]è deprecato e $(())dovrebbe essere favorito.


7
Potresti voler scambiare questi due, poiché la pagina man di bash 4.x afferma che $ [] è deprecato e verrà rimosso nelle versioni future.
tink

2
Grazie, non ero a conoscenza.
OnnipotentEntity

157

Trovo molto pulito usare la variabile interna "$ SECONDS"

SECONDS=0 ; sleep 10 ; echo $SECONDS


10
Unico successo =)
Lon Kaut

1
Hai bisogno di successo, usa il tuo
Gromish

3
$SECONDSfunziona davvero per / bin / bash. Non funziona per / bin / dash, la shell predefinita in Debian e Ubuntu.
Cameron Taggart

2
Lo svantaggio di questa soluzione è che misura solo secondi interi, cioè non utilizzabile se è necessaria una precisione inferiore al secondo.
Czechnology

@Czechnology sì, se usi sleep 0.5sopra, il risultato a volte è 0, a volte 1 (almeno per Bash 5.0.3).
jarno

52

Stai tentando di eseguire il numero nel ENDTIMEcomando as. Dovresti anche vedere un errore come 1370306857: command not found. Usa invece l' espansione aritmetica :

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

Puoi anche salvare i comandi in uno script separato commands.she utilizzare il comando time:

time commands.sh

28

Puoi usare la timeparola chiave di Bash qui con una stringa di formato appropriata

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

Ecco cosa diceTIMEFORMAT il riferimento su :

Il valore di questo parametro viene utilizzato come stringa di formato che specifica come time devono essere visualizzate le informazioni di temporizzazione per le pipeline con prefisso con la parola riservata. Il %carattere " " introduce una sequenza di escape che viene espansa a un valore temporale o ad altre informazioni. Le sequenze di escape e il loro significato sono i seguenti; le parentesi graffe denotano porzioni facoltative.

%%

    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. 

La p opzionale è una cifra che specifica la precisione, il numero di cifre frazionarie dopo un punto decimale. Un valore pari a 0 non causa l'output del punto decimale o della frazione. È possibile specificare al massimo tre posizioni dopo il punto decimale; i valori di p maggiori di 3 vengono modificati in 3. Se p non è specificato, viene utilizzato il valore 3.

L'opzionale lspecifica un formato più lungo, inclusi i minuti, del formato MMmSS.FFs. Il valore di p determina se la frazione è inclusa o meno.

Se questa variabile non è impostata, Bash si comporta come se avesse il valore

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

Se il valore è nullo, non viene visualizzata alcuna informazione di temporizzazione. Quando viene visualizzata la stringa di formato, viene aggiunta una nuova riga finale.


10

Per numeri più grandi potremmo voler stampare in un formato più leggibile. L'esempio seguente fa lo stesso degli altri ma stampa anche in formato "umano":

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."
}

Test semplice:

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

Produzione:

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.

Per utilizzare in uno script come descritto in altri post (cattura il punto di inizio quindi chiama la funzione con l'ora di fine:

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

9

Prova il codice seguente:

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

5

Questa è un'alternativa di una riga alla funzione di Mike Q:

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

Bello! Di solito sono molto prolisso con il mio codice bash, questo è fantastico.
Mike Q

La combinazione di questo con SECONDSla risposta di Lon Kaut e tenendo presente che $ / $ {} non è necessario sulle variabili aritmetiche rende il codice così breve che potrebbe anche essere utilizzato in linea:echo "$((SECONDS/3600))h $(((SECONDS/60)%60))m $((SECONDS%60))s"
ssc

2

prova a utilizzare il tempo con l'opzione dei secondi trascorsi:

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

o \time -f%e sleep 1in una bash interattiva.

vedi la pagina man del tempo:

Gli utenti della shell bash devono utilizzare un percorso esplicito per eseguire il comando time esterno e non la variante incorporata della shell. Sul sistema in cui time è installato in / usr / bin, il primo esempio diventerebbe / usr / bin / time wc / etc / hosts

e

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

1
/bin/timenon funzionerà qui: OP menziona un blocco . Quindi abbiamo davvero bisogno della parola chiave timequi.
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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.