Reputation: 233
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.
Upvotes: 21
Views: 64495
Reputation: 804
As a follow-on to @Michael Behrens' answer, here's a programmatic way to extract the uptime by parsing the JSON output of system_profiler
. It does require jq (brew install jq
).
This has some advantages. It should be more robust than relying on text processing with grep + awk, and allows the output language as well as the format to be customized.
The code is below, or you can find it on GitHub. It can be pasted as a one-liner, added as a shell function, or saved as a script.
system_profiler SPSoftwareDataType -json |
jq --raw-output --argjson labels '[ "day", "hour", "minute", "second" ]' '
.SPSoftwareDataType[0].uptime[3:] // empty | split(":") as $uptime |
def pprint:
($uptime[.] | tonumber) as $val |
if $val == 0 then empty else
"\($val) \($labels[.])" + (if $val == 1 then "" else "s" end)
end;
[range($uptime|length)] | map(pprint) | join(", ")'
2 days, 9 hours, 52 minutes, 34 seconds
An example of localizing to Spanish by modifying the labels
string passed in via --argjson
:
jq --raw-output --argjson labels '[ "día", "hora", "minuto", "segundo" ]' ...
Output:
2 días, 9 horas, 52 minutos, 34 segundos
system_profiler SPSoftwareDataType -json |
jq --raw-output --argjson labels '[ "day", "hour", "minute", "second" ]' '
.SPSoftwareDataType[0].uptime[3:] // empty | split(":") as $uptime |
def pprint:
($uptime[.] | tonumber) as $val |
"\($val) \($labels[.])" + (if $val == 1 then "" else "s" end);
[1] | map(pprint) | join(", ")'
Output:
12 hours
system_profiler SPSoftwareDataType -json |
jq --raw-output '
.SPSoftwareDataType[0].uptime[3:] // empty |
split(":") | map(tonumber) as $uptime |
[86400, 3600, 60] as $multipliers |
reduce range($uptime|length) as $i (0; . + ($uptime[$i] * ($multipliers[$i] // 1)))'
Output
216416
Upvotes: 1
Reputation: 1157
For MacOS, I like the answer provided by Kenneth on Apple Discussions. Basically you can get the desired output with this command:
system_profiler SPSoftwareDataType -detailLevel mini | grep days | awk -F: '{print $2}'
Example output:
7 days, 2 hours, 39 minutes
Upvotes: 1
Reputation: 14467
Solution: In order to get the linux uptime in seconds, Go to bash and type cat /proc/uptime
.Parse the first number and convert it according to your requirement.
From RedHat documentation:
This file contains information detailing how long the system has been on since its last restart. The output of
/proc/uptime
is quite minimal:350735.47 234388.90
The First number is the total number of seconds the system has been up.
The Second number is how much of that time the machine has spent idle, in seconds.
Upvotes: 10
Reputation:
uptime_minutes() {
set `uptime -p`
local minutes=0
shift
while [ -n "$1" ]; do
case $2 in
day*)
((minutes+=$1*1440))
;;
hour*)
((minutes+=$1*60))
;;
minute*)
((minutes+=$1))
;;
esac
shift
shift
done
echo $minutes
}
Upvotes: 1
Reputation: 51
I made a universal shell script, for systems which support uptime -p
like newer linux and for those that don't, like Mac OS X.
#!/bin/sh
uptime -p >/dev/null 2>&1
if [ "$?" -eq 0 ]; then
# Supports most Linux distro
# when the machine is up for less than '0' minutes then
# 'uptime -p' returns ONLY 'up', so we need to set a default value
UP_SET_OR_EMPTY=$(uptime -p | awk -F 'up ' '{print $2}')
UP=${UP_SET_OR_EMPTY:-'less than a minute'}
else
# Supports Mac OS X, Debian 7, etc
UP=$(uptime | sed -E 's/^[^,]*up *//; s/mins/minutes/; s/hrs?/hours/;
s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/;
s/^1 hours/1 hour/; s/ 1 hours/ 1 hour/;
s/min,/minutes,/; s/ 0 minutes,/ less than a minute,/; s/ 1 minutes/ 1 minute/;
s/ / /; s/, *[[:digit:]]* users?.*//')
fi
echo "up $UP"
Referenced John1024 answer with my own customizations.
Upvotes: 4
Reputation: 113814
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.
-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.
.
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
-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
.
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."
}'
Upvotes: 44
Reputation: 29
For this:
More simple is:
uptime -p | cut -d " " -f2-
Upvotes: 2
Reputation: 2918
This answer is pretty specific for the uptime
shipped in OS X, but takes into account any case of output.
#!/bin/bash
INFO=`uptime`
echo $INFO | awk -F'[ ,:\t\n]+' '{
msg = "↑ "
if ($5 == "day" || $5 == "days") { # up for a day or more
msg = msg $4 " " $5 ", "
n = $6
o = $7
} else {
n = $4
o = $5
}
if (int(o) == 0) { # words evaluate to zero
msg = msg int(n)" "o
} else { # hh:mm format
msg = msg int(n)" hr"
if (n > 1) { msg = msg "s" }
msg = msg ", " int(o) " min"
if (o > 1) { msg = msg "s" }
}
print "[", msg, "]"
}'
Some example possible outputs:
22:49 up 24 secs, 2 users, load averages: 8.37 2.09 0.76
[ ↑ 24 secs ]
22:50 up 1 min, 2 users, load averages: 5.59 2.39 0.95
[ ↑ 1 min ]
23:39 up 51 mins, 3 users, load averages: 2.18 1.94 1.74
[ ↑ 51 mins ]
23:54 up 1:06, 3 users, load averages: 3.67 2.57 2.07
[ ↑ 1 hr, 6 mins ]
16:20 up 120 days, 10:46, 3 users, load averages: 1.21 2.88 0.80
[ ↑ 120 days, 10 hrs, 46 mins ]
Upvotes: 0
Reputation: 531
Just vor completeness... what's about:
$ uptime -p
up 2 weeks, 3 days, 14 hours, 27 minutes
Upvotes: 35
Reputation: 941
For the sake of variety, here's an example with sed:
My raw output:
$ uptime
15:44:56 up 3 days, 22:58, 7 users, load average: 0.48, 0.40, 0.31
Converted output:
$uptime|sed 's/.*\([0-9]\+ days\), \([0-9]\+\):\([0-9]\+\).*/\1, \2 hours, \3 minutes./'
3 days, 22 hours, 58 minutes.
Upvotes: 1