# Shell – How to determine the amount of time left in a “sleep”

shellsleep

I have:

``````sleep 210m && for i in \$(seq 1 5); do echo -e '\a'; sleep 0.5; done
``````

running as a simple, no-frills timer to remind me when something should be done. That `sleep 210m` is PID 25347.

I'm trying to figure out how much time is left in the sleep. The best I've come up with, with me putting in the original sleep amount (210 minutes) is:

``````\$ echo "210 60 * \$(ps -o etimes= 25347) - 60 ~ r n [:] P p" | dc
78:11
``````

(Explanation: First bit computes the number of seconds in the original sleep; the `\$(ps…)` bit gets the time since sleep started in seconds, then the rest subtracts them and displays in minutes and seconds.)

It occurs to me this would be useful in general; is there a better way to do this? Or at least a clever way to parse the sleep time from `ps -o args`?

Supporting GNU or Solaris 11 `sleep` arguments (one or more `<double>[smhd]` durations, so would also work with traditional implementations that support only one decimal integer number (like on FreeBSD), but not with those accepting more complex arguments like ISO-8601 durations). Using `etime` instead of `etimes` as that's more portable (standard Unix).

``````remaining_sleep_time() { # arg: pid
ps -o etime= -o args= -p "\$1" | perl -MPOSIX -lane '
%map = qw(d 86400 h 3600 m 60 s 1);
\$F[0] =~ /(\d+-)?(\d+:)?(\d+):(\d+)/;
\$t = -(\$4+60*(\$3+60*(\$2+24*\$1)));
for (@F[2..\$#F]) {
s/\?//g;
(\$n, \$p) = strtod(\$_);
\$n *= \$map{substr(\$_, -\$p)} if \$p;
\$t += \$n
}
print \$t'
}
``````

(the `s/\?//g` is to get rid of the `?` characters that `procps`' `ps` uses as replacement for control characters. Without it, it would fail to parse `sleep \$'\r1d'` or `sleep \$'\t1d'`... Unfortunately, in some locales, including the `C` locale, it uses `.` instead of `?`. Not much we can do in that case as there's no way to tell a `\t5d` from a `.5d` (half day)).

Pass the pid as argument.

That also assumes the `argv[0]` passed to `sleep` doesn't contain blanks and that the number of arguments is small enough that it's not truncated by `ps`.

Examples:

``````\$ sleep infinity & remaining_sleep_time "\$!"
Inf
\$ sleep 0xffp-6d &
\$ remaining_sleep_time "\$!"
344249
\$ sleep 1m 1m 1m 1m 1m & remaining_sleep_time "\$!"
300
``````

For a `[[[ddd-]HH:]MM:]SS` output instead of just the number of seconds, replace the `print \$t` with:

``````\$output = "";
for ([60,"%02d\n"],[60,"%02d:"],[24,"%02d:"],[inf,"%d-"]) {
last unless \$t;
\$output = sprintf(\$_->[1], \$t % \$_->[0]) . \$output;
\$t = int(\$t / \$_->[0])
}
printf "%s", \$output;
``````