Bash-Skript zur Berechnung der verstrichenen Zeit


117

Ich schreibe ein Skript in Bash, um die Zeit zu berechnen, die für die Ausführung meiner Befehle vergangen ist. Beachten Sie:

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

Ich denke, meine Logik ist korrekt, aber am Ende habe ich den folgenden Ausdruck:

"Es dauert Sekunden, um diese Aufgabe abzuschließen ..."

Stimmt etwas mit meiner String-Bewertung nicht?

Ich glaube, Bash-Variablen sind untypisiert. Ich würde mich freuen, wenn es in Bash trotzdem eine "String to Integer" -Methode gibt.

Antworten:


83

Entweder $(())oder $[]wird zur Berechnung des Ergebnisses einer arithmetischen Operation verwendet. Sie verwenden, indem Sie $()einfach die Zeichenfolge nehmen und als Befehl auswerten. Es ist eine subtile Unterscheidung. Hoffe das hilft.

Wie Tink in den Kommentaren zu dieser Antwort hervorhob, $[]ist es veraltet und $(())sollte bevorzugt werden.


7
Möglicherweise möchten Sie diese beiden vertauschen, da in der Manpage bash 4.x angegeben ist, dass $ [] veraltet ist und in zukünftigen Versionen entfernt wird.
Tink

2
Danke, ich wusste es nicht.
OmnipotentEntity

157

Ich finde es sehr sauber, die interne Variable "$ SECONDS" zu verwenden.

SECONDS=0 ; sleep 10 ; echo $SECONDS


10
Einziger Erfolg =)
Lon Kaut

1
Brauchen Sie Erfolg, verwenden Sie Ihre
Gromish

3
$SECONDSfunktioniert in der Tat für / bin / bash. Es funktioniert nicht für / bin / dash, die Standard-Shell in Debian und Ubuntu.
Cameron Taggart

2
Der Nachteil dieser Lösung ist, dass sie nur ganze Sekunden misst, dh nicht verwendet werden kann, wenn Sie eine Genauigkeit von weniger als einer Sekunde benötigen.
Czechnology

@Czechnology ja, wenn Sie sleep 0.5oben verwenden, ist das Ergebnis manchmal 0, manchmal 1 (zumindest nach Bash 5.0.3).
jarno

52

Sie versuchen, die Nummer in ENDTIMEals Befehl auszuführen . Sie sollten auch einen Fehler wie sehen 1370306857: command not found. Verwenden Sie stattdessen die arithmetische Erweiterung :

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

Sie können die Befehle auch in einem separaten Skript speichern commands.shund den Befehl time verwenden:

time commands.sh

28

Sie können das timeSchlüsselwort von Bash hier mit einer geeigneten Formatzeichenfolge verwenden

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

Folgendes sagtTIMEFORMAT die Referenz :

Der Wert dieses Parameters wird als Formatzeichenfolge verwendet, die angibt, wie die Zeitinformationen für Pipelines mit dem vorangestellten time reservierten Wort angezeigt werden sollen. Das %Zeichen ' ' führt eine Escape-Sequenz ein, die auf einen Zeitwert oder andere Informationen erweitert wird. Die Escape-Sequenzen und ihre Bedeutungen sind wie folgt; Die Klammern kennzeichnen optionale Teile.

%%

    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. 

Das optionale p ist eine Ziffer, die die Genauigkeit und die Anzahl der Bruchstellen nach einem Dezimalpunkt angibt. Bei einem Wert von 0 wird kein Dezimalpunkt oder Bruch ausgegeben. Es dürfen höchstens drei Stellen nach dem Dezimalpunkt angegeben werden. Werte von p größer als 3 werden in 3 geändert. Wenn p nicht angegeben ist, wird der Wert 3 verwendet.

Das optionale lFormat gibt ein längeres Format einschließlich Minuten des Formulars MMmSS.FFs an. Der Wert von p bestimmt, ob der Bruch enthalten ist oder nicht.

Wenn diese Variable nicht gesetzt ist, verhält sich Bash so, als hätte es den Wert

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

Wenn der Wert null ist, werden keine Zeitinformationen angezeigt. Eine nachgestellte neue Zeile wird hinzugefügt, wenn die Formatzeichenfolge angezeigt wird.


10

Bei größeren Zahlen möchten wir möglicherweise in einem besser lesbaren Format drucken. Das folgende Beispiel funktioniert genauso wie andere, druckt jedoch auch im "menschlichen" Format:

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

Einfaches Testen:

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

Ausgabe:

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.

So verwenden Sie ein Skript wie in anderen Beiträgen beschrieben (erfassen Sie den Startpunkt und rufen Sie die Funktion mit der Endzeit auf:

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

9

Versuchen Sie den folgenden Code:

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


2

Versuchen Sie, die Zeit mit der Option "Verstrichene Sekunden" zu verwenden:

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

oder \time -f%e sleep 1in interaktiver Bash.

Siehe die Zeitmanpage:

Benutzer der Bash-Shell müssen einen expliziten Pfad verwenden, um den externen Zeitbefehl und nicht die in die Shell integrierte Variante auszuführen. Auf einem System, auf dem time in / usr / bin installiert ist, lautet das erste Beispiel / usr / bin / time wc / etc / hosts

und

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

1
/bin/timewird hier nicht funktionieren: OP erwähnt einen Block . Wir brauchen also wirklich das Schlüsselwort timehier.
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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.