Как я могу создать секундомер в Bash?

Я создал простой секундомер (функция bash) для подсчета времени, но пока он показывает текущее время в миллисекундах.

Код:

function stopwatch() {
    date +%H:%M:%S:%N
    while true; do echo -ne "`date +%H:%M:%S:%N`\r"; done;
}

Я попытался изменить его, как объяснено в этом ответе, но он работает только со второй после Unix Epoch.

Когда я использовал date формат +%s.%N вычитание из ответа выше перестало работать из-за того, что вычитание bash занимает только целое число.

Как я могу решить это и иметь терминальный секундомер, который печатает время так:

0.000000000
0.123123123
0.435345345
(and so on..)

?

5 ответов

Решение

Один возможный (и хакерский) механизм, который может работать в течение дня:

$ now=$(date +%s)sec
$ while true; do
     printf "%s\r" $(TZ=UTC date --date now-$now +%H:%M:%S.%N)
     sleep 0.1
  done

Примечание: это быстрое решение. Лучшие решения должны быть доступны...

Если вы хотите что-то простое, включающее минуты, секунды и центсекунды, например, традиционный секундомер, вы можете использовать sw.

ЮЗ

устанавливать

wget -q -O - http://git.io/sinister | sh -s -- -u https://raw.githubusercontent.com/coryfklein/sw/master/sw

использование

# start a stopwatch from 0, save start time in ~/.sw
sw

# resume the last run stopwatch
sw --resume 

Вот мой:

time cat

вы нажимаете Ctrl-c или Ctrl-d чтобы остановиться и показать время. Первое число - время.

Я переработал его в этот псевдоним bash

alias stopwatch="echo Press Ctrl-c to stop the timer; TIMEFORMAT=%R; time cat; unset TIMEFORMAT"

Вот более приятная функция, которую я взял недавно:

function stopwatch() {
    local BEGIN=$(date +%s)
    echo Starting Stopwatch...

    while true; do
        local NOW=$(date +%s)
        local DIFF=$(($NOW - $BEGIN))
        local MINS=$(($DIFF / 60))
        local SECS=$(($DIFF % 60))
        local HOURS=$(($DIFF / 3600))
        local DAYS=$(($DIFF / 86400))

        printf "\r%3d Days, %02d:%02d:%02d" $DAYS $HOURS $MINS $SECS
        sleep 0.5
    done
}

Исходя из сути Равалудина:

function stopwatch() {
  local BEGIN=$(date +%s)

  while true; do
    local NOW=$(date +%s)
    local DIFF=$(($NOW - $BEGIN))
    local MINS=$(($DIFF / 60 % 60))
    local SECS=$(($DIFF % 60))
    local HOURS=$(($DIFF / 3600 % 24))
    local DAYS=$(($DIFF / 86400))
    local DAYS_UNIT
    [ "$DAYS" == 1 ] && DAYS_UNIT="Day" || DAYS_UNIT="Days"

    printf "\r  %d %s, %02d:%02d:%02d  " $DAYS $DAYS_UNIT $HOURS $MINS $SECS
    sleep 0.25
  done
}

Для людей, которые не знакомы с этим: на английском языке, только когда это 1 мы используем единственное число - день. Когда это 0, 2, 3, 4, 5..., мы используем множественное число "Дней", поэтому обратите внимание, что это 0 Days,

Вот еще один подход к секундомеру bash, основанный на других ответах в этой теме. Отличия этой версии от других включают:

  • В этой версии используется арифметика bash вместо вызова bc который я обнаружил (по времени) намного меньше времени процессора.
  • Я обратился к 25-часовому ограничению, на которое кто-то указал, добавив 24 часа к часовой части для каждого прошедшего дня. (Итак, теперь я предполагаю, что это ограничение на 31 день.)
  • Я оставляю курсор справа от вывода, в отличие от версии в принятом ответе. Таким образом, вы можете легко измерить круги (или, в более общем смысле, отметить время важных событий), просто нажав клавишу ввода, что переместит таймер на следующую строку, оставив время при нажатии клавиши видимым.
#!/bin/bash

start_time=$(date +%s)

while true; do
  current_time=$(date +%s)
  seconds_elapsed=$(( $current_time - $start_time ))
  timestamp=$(date -d"@$seconds_elapsed" -u +%-d:%-H:%-M:%-S)

  IFS=':' read -r day hour minute second <<< "$timestamp"
  hour="$(( $hour+24*($day-1) ))"

  printf "\r%02d:%02d:%02d" $hour $minute $second
  sleep 0.5
done;

Вот пример вывода из работы stopwatch(как исполняемый сценарий в PATH) и нажатие клавиши возврата через 7 и 18 секунд, а нажатие Ctrl-C примерно через 9 минут:

$ stopwatch
00:00:07
00:00:18
00:09:03^C
$

Примечания:

  • Я использую +%-d:%-H:%-M:%-S выходной формат даты (эти дефисы означают "пожалуйста, оставьте любой начальный ноль"), потому что printf, кажется, интерпретирует строки цифр с начальным нулем как восьмеричные и в конечном итоге жалуется на недопустимые значения.
  • Я избавился от наносекунд просто потому, что для моих целей мне не нужна точность, превышающая 1 секунду. Поэтому я скорректировалsleep продолжительность быть больше, чтобы сэкономить на вычислениях.

Для вычитания вы должны использовать bc (An arbitrary precision calculator language).

Вот пример кода, который соответствует вашим требованиям:

function stopwatch() {
    date1=`date +%s.%N`
    while true; do
        curr_date=`date +%s.%N`
        subtr=`echo "$curr_date - $date1" | bc`
        echo -ne "$subtr\r";
        sleep 0.03
    done;
}

дополнительный sleep добавляется для снижения загрузки процессора (без него на моей машине это было почти 15%, и с этим sleep он снизился до 1%).

Другие вопросы по тегам