Bash format uptime to show days, hours, minutes

user1799031 picture user1799031 · Feb 5, 2015 · Viewed 41.7k times · Source

I'm using uptime in bash in order to get the current runtime of the machine. I need to grab the time and display a format like 2 days, 12 hours, 23 minutes.

Answer

John1024 picture John1024 · Feb 5, 2015

My uptime produces output that looks like:

$ uptime
 12:49:10 up 25 days, 21:30, 28 users,  load average: 0.50, 0.66, 0.52

To convert that to your format:

$ uptime | awk -F'( |,|:)+' '{print $6,$7",",$8,"hours,",$9,"minutes."}'
25 days, 21 hours, 34 minutes.

How it works

  • -F'( |,|:)+'

    awk divides its input up into fields. This tells awk to use any combination of one or more of space, comma, or colon as the field separator.

  • print $6,$7",",$8,"hours,",$9,"minutes."

    This tells awk to print the sixth field and seventh fields (separated by a space) followed by a comma, the 8th field, the string hours, the ninth field, and, lastly, the string minutes..

Handling computers with short uptimes using sed

Starting from a reboot, my uptime produces output like:

 03:14:20 up 1 min,  2 users,  load average: 2.28, 1.29, 0.50
 04:12:29 up 59 min,  5 users,  load average: 0.06, 0.08, 0.48
 05:14:09 up  2:01,  5 users,  load average: 0.13, 0.10, 0.45
 03:13:19 up 1 day, 0 min,  8 users,  load average: 0.01, 0.04, 0.05
 04:13:19 up 1 day,  1:00,  8 users,  load average: 0.02, 0.05, 0.21
 12:49:10 up 25 days, 21:30, 28 users,  load average: 0.50, 0.66, 0.52

The following sed command handles these formats:

uptime | sed -E 's/^[^,]*up *//; s/, *[[:digit:]]* users.*//; s/min/minutes/; s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/' 

With the above times, this produces:

1 minutes
59 minutes
2 hours, 1 minutes
1 day, 0 minutes
1 day,  1 hours, 0 minutes
25 days, 21 hours, 30 minutes

How it works

  • -E turns on extended regular expression syntax. (On older GNU seds, use -r in place of -E)

  • s/^[^,]*up *//

    This substitutes command removes all text up to up.

  • s/, *[[:digit:]]* users.*//

    This substitute command removes the user count and all text which follows it.

  • s/min/minutes/

    This replaces min with minutes.

  • s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/'

    If the line contains a time in the hh:mm format, this separates the hours from the minutes and replaces it with hh hours, mm minutes.

Handling computers with short uptimes using awk

uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'

On the same test cases as above, this produces:

0 days, 0 hours, 1 minutes.
0 days, 0 hours, 59 minutes.
0 days, 2 hours, 1 minutes.
1 days, 0 hours, 0 minutes.
1 days, 1 hours, 0 minutes.
25 days, 21 hours, 30 minutes.

For those who prefer awk code spread out over multiple lines:

uptime | awk -F'( |,|:)+' '{
    d=h=m=0;
    if ($7=="min")
        m=$6;
    else {
        if ($7~/^day/) { d=$6; h=$8; m=$9}
        else {h=$6;m=$7}
        }
    }
    {
        print d+0,"days,",h+0,"hours,",m+0,"minutes."
    }'