bash script to get the spent time from a file - linux

I have a log file that shows switch time between my scripts:
Tue Oct 24 11:57:54 IRST 2017 Script switched from abc to XYZ
Tue Oct 24 14:03:41 IRST 2017 Script switched from XYZ to ZEN
Tue Oct 24 15:43:16 IRST 2017 Script switched from ZEN to XYZ
Tue Oct 24 17:07:25 IRST 2017 Script switched from XYZ to ZEN
Tue Oct 24 18:40:48 IRST 2017 Script switched from ZEN to XLS
Tue Oct 24 19:52:26 IRST 2017 Script switched from XLS to XYZ
Tue Oct 24 20:20:30 IRST 2017 Script switched from XYZ to ZEN
Tue Oct 24 20:36:06 IRST 2017 Script switched from ZEN to XLS
Tue Oct 24 21:01:03 IRST 2017 Script switched from XLS to XYZ
Tue Oct 24 21:47:47 IRST 2017 Script switched from XYZ to ZEN
How do I get total time spent on each script with bash
So the output shows like this:
abc 2 hours 30 min 40 sec
XYZ 3 hours 23 min 45 sec
zen ...
XLS ...

Assuming you have a log file named test.txt, following script should work,
#!/bin/bash
dtime=0
sname=""
while read line
do
_dtime=$(echo "$line" | awk '{print $1,$2,$3,$4}')
_sname=$(echo "$line" | awk '{print $10}')
_dtimesec=$(date +%s -d "$_dtime")
_timediff=$(( _dtimesec - dtime ))
[ "x$sname" != "x" ] && printf "$sname %d hours %d minutes %d seconds\n" $(($_timediff/3600)) $(($_timediff%3600/60)) $(($_timediff%60))
dtime=$_dtimesec
sname=$_sname
done < test.txt
This will produce an output like the following:
]$ ./test
abc 2 hours 5 minutes 47 seconds
XYZ 1 hours 39 minutes 35 seconds
ZEN 1 hours 24 minutes 9 seconds
XYZ 1 hours 33 minutes 23 seconds
ZEN 1 hours 11 minutes 38 seconds
XLS 0 hours 28 minutes 4 seconds
XYZ 0 hours 15 minutes 36 seconds
ZEN 0 hours 24 minutes 57 seconds
XLS 0 hours 46 minutes 44 seconds
EDIT
In order to find total amount of time spent by each script, this modified script should do the job:
#!/bin/bash
dtime=0
sname=""
namearr=()
timearr=()
while read line
do
_dtime=$(echo "$line" | awk '{print $1,$2,$3,$4}')
_sname=$(echo "$line" | awk '{print $10}')
_dtimesec=$(date +%s -d "$_dtime")
_timediff=$(( _dtimesec - dtime ))
_rc=1
for n in "${!namearr[#]}"
do
if [ "${namearr[$n]}" == "$_sname" ]; then
export _rc=$?
export ind=$n
break;
else
export _rc=1
fi
done
if [ $_rc -eq 0 ]; then
timearr[$ind]=$(( ${timearr[$ind]} + _timediff ))
else
if [ $dtime -eq 0 ] && [ "x$sname" == "x" ]; then
:
else
namearr+=($_sname)
timearr+=($_timediff)
fi
fi
dtime=$_dtimesec
sname=$_sname
done < test.txt
echo "Total time spent by each script:"
echo
for i in "${!namearr[#]}"
do
_gtime=${timearr[$i]}
printf "${namearr[$i]} %d hours %d minutes %d seconds\n" $(($_gtime/3600)) $(($_gtime%3600/60)) $(($_gtime%60))
done
Result:
$ ./test
Total time spent by each script:
XYZ 4 hours 44 minutes 44 seconds
ZEN 3 hours 28 minutes 34 seconds
XLS 1 hours 36 minutes 35 seconds

You can use the following gawk program:
time_spent.awk
BEGIN {
months["Jan"] = "01"
months["Feb"] = "02"
months["Mar"] = "03"
months["Apr"] = "04"
months["May"] = "05"
months["Jun"] = "06"
months["Jul"] = "07"
months["Aug"] = "08"
months["Seb"] = "09"
months["Oct"] = "10"
months["Nov"] = "11"
months["Dec"] = "12"
}
{
split($4, time, ":")
# mktime() manual: https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html
now = mktime($6" "months[$2]" "$3" "time[1]" "time[2]" "time[3])
prv = $(NF-2)
cur = $(NF)
start[cur] = now
spent[prv]+=start[prv]?now-start[prv]:0
}
END {
for(i in spent) {
printf "%s seconds spent in %s\n", spent[i], i
}
}
Save it into a file time_spent.awk and execute it like this:
gawk -f time_spent.awk input.log
Output from the above example:
5795 seconds spent in XLS
0 seconds spent in abc
17084 seconds spent in XYZ
12514 seconds spent in ZEN

#!/usr/bin/env python
import sys
from time import strptime
from datetime import datetime
intervals = (
('weeks', 604800), # 60 * 60 * 24 * 7
('days', 86400), # 60 * 60 * 24
('hours', 3600), # 60 * 60
('minutes', 60),
('seconds', 1),
)
def display_time(seconds, granularity=2):
result = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ' '.join(result[:granularity])
with open(sys.argv[1], "rb") as df:
lines = df.readlines()
totals = {}
for i in range(len(lines)-1):
(_,t1,t2,t3,_,t4,_,_,_,_,_,scr) = lines[i].strip().split(' ')
st = datetime.strptime(' '.join([t1,t2,t3,t4]), "%b %d %H:%M:%S %Y")
(_,t1,t2,t3,_,t4,_,_,_,_,_,_) = lines[i+1].strip().split(' ')
et = datetime.strptime(' '.join([t1,t2,t3,t4]), "%b %d %H:%M:%S %Y")
if scr not in totals:
totals[scr] = 0
totals[scr] += (et-st).seconds
print("{} {}".format(scr,display_time((et-st).seconds, 3)))
print("\nTotals:")
for scr in totals:
print("{} {}".format(scr,display_time(totals[scr], 3)))
Here is the output, assuming your times are in a file named logfile:
$ ./times.py logfile
XYZ 2 hours 5 minutes 47 seconds
ZEN 1 hour 39 minutes 35 seconds
XYZ 1 hour 24 minutes 9 seconds
ZEN 1 hour 33 minutes 23 seconds
XLS 1 hour 11 minutes 38 seconds
XYZ 28 minutes 4 seconds
ZEN 15 minutes 36 seconds
XLS 24 minutes 57 seconds
XYZ 46 minutes 44 seconds
Totals:
XLS 1 hour 36 minutes 35 seconds
XYZ 4 hours 44 minutes 44 seconds
ZEN 3 hours 28 minutes 34 seconds
$
Note: I lifted the handy display_time function from here: Python function to convert seconds into minutes, hours, and days.

Related

Last date of each month in a calender year [duplicate]

As we know that each year have the following max day in each month as follows:
Jan - 31 days
Feb - 28 days / 29 days (leap year)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
How to I get bash to return the value (last day of each month) for the current year without using if else or switch or while loop?
my take:
for m in {1..12}; do
date -d "$m/1 + 1 month - 1 day" "+%b - %d days";
done
To explain: for the first iteration when m=1 the -d argument is "1/1 + 1 month - 1 day" and "1/1" is interpreted as Jan 1st. So Jan 1 + 1 month - 1 day is Jan 31. Next iteration "2/1" is Feb 1st, add a month subtract a day to get Feb 28 or 29. And so on.
cat <<EOF
Jan - 31 days
Feb - `date -d "yesterday 3/1" +"%d"` days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
EOF
cal $(date +"%m %Y") |
awk 'NF {DAYS = $NF}; END {print DAYS}'
This uses the standard cal utility to display the specified month, then runs a simple Awk script to pull out just the last day's number.
Assuming you allow "for", then the following in bash
for m in {1..12}; do
echo $(date -d $m/1/1 +%b) - $(date -d "$(($m%12+1))/1 - 1 days" +%d) days
done
produces this
Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
Note: I removed the need for cal
For those that enjoy trivia:
Number months from 1 to 12 and look at the binary representation in four
bits {b3,b2,b1,b0}. A month has 31 days if and only if b3 differs from b0.
All other months have 30 days except for February.
So with the exception of February this works:
for m in {1..12}; do
echo $(date -d $m/1/1 +%b) - $((30+($m>>3^$m&1))) days
done
Result:
Jan - 31 days
Feb - 30 days (wrong)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
Try using this code
date -d "-$(date +%d) days month" +%Y-%m-%d
Returns the number of days in the month compensating for February changes in leap years without looping or using an if statement
This code tests date to see if Feb 29th of the requested year is valid, if so then it updates the second character in the day offset string. The month argument selects the respective substring and adds the month difference to 28.
function daysin()
{
s="303232332323" # normal year
((!($2%4)&&($2%100||!($2%400)))) && s=313232332323 # leap year
echo $[ ${s:$[$1-1]:1} + 28 ]
}
daysin $1 $2 #daysin [1-12] [YYYY]
On a Mac which features BSD date you can just do:
for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
Quick Explanation
-v stands for adjust. We are adjusting the date to:
-v1d stands for first day of the month
-v"$i"m defined the month e.g. (-v2m for Feb)
-v-1d minus one day (so we're getting the last day of the previous month)
"+%d" print the day of the month
for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
31
28
31
30
31
30
31
31
30
31
30
You can add year of course. See examples in the manpage (link above).
Contents of script.sh:
#!/bin/bash
begin="-$(date +'%-m') + 2"
end="10+$begin"
for ((i=$begin; i<=$end; i++)); do
echo $(date -d "$i month -$(date +%d) days" | awk '{ printf "%s - %s days", $2, $3 }')
done
Results:
Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
for m in $(seq 1 12); do cal $(date +"$m %Y") | grep -v "^$" |tail -1|grep -o "..$"; done
iterate from 1 to 12 (for...)
print calendar table for each month (cal...)
remove empty lines from output (grep -v...)
print last number in the table (tail...)
There is no sense, to avoid using cal, because it is required by POSIX, so should be there
A variation for the accepted answer to show the use of "yesterday"
$ for m in {1..12}; do date -d "yesterday $m/1 + 1 month" "+%b - %d days"; done
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
How it works?
Show the date of yesterday for the date "month/1" after adding 1 month
I needed this few times, so when in PHP comes with easy in bash is not,
so I used this till throw me error "invalid arithemtic operator"
and even with warrings in spellcheck ( "mt" stands for month, "yr" for year )
last=$(echo $(cal ${mt} ${yr}) | awk '{print $NF}')
so this works fine...
### get last day of month
#
# implement from PHP
# src: https://www.php.net/manual/en/function.cal-days-in-month.php
#
if [ $mt -eq 2 ];then
if [[ $(bc <<< "${yr} % 4") -gt 0 ]];then
last=28
else
if [[ $(bc <<< "${yr} % 100") -gt 0 ]];then
last=29
else
[[ $(bc <<< "${yr} % 400") -gt 0 ]] && last=28 || last=29
fi
fi
else
[[ $(bc <<< "(${mt}-1) % 7 % 2") -gt 0 ]] && last=30 || last=31
fi
Building on patm's answer using BSD date for macOS (patm's answer left out December):
for i in {1..12}; do date -v1m -v1d -v+"$i"m -v-1d "+%b - %d days"; done
Explanation:
-v, when using BSD date, means adjust date to:
-v1m means go to first month (January of current year).
-v1d means go to first day (so now we are in January 1).
-v+"$i"m means go to next month.
-v-1d means subtract one day. This gets the last day of the previous month.
"+%b - %d days" is whatever format you want the output to be in.
This will output all the months of the current year and the number of days in each month. The output below is for the as-of-now current year 2022:
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

Get date with same day in month

I want to get all dates with the same day of week.
inputDate="2021/08/25"
That means I should get all the same day of week as inputDate.
outputDates="2021/08/04,2021/08/11,2021/08/18,2021/08/25"
I only got this so far..
inputDate="2021/08/25"
dd=$(date -d "$inputDate" +"%Y/%m/%d")
So what I'm planning is to do "date -7" and loop 5 times forward and backward and collect it then check if value of month is still the same with inputDate if not then drop it
Do you have any way to do this?
Using only shell, the easyest way to get all weekdays from a month is by using cal command:
cal -n1 8 2021
outputs:
August 2021
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Then you can filter using sed, awk or other tools to reach your goal.
Example:
year=2021
month=8
day=25
weekday_number="$(date -d$year-$month-$day +%w)"
cn=$(($weekday_number + 1))
cal -n1 $month $year |
sed -r 's/(..)\s/\1\t/g;s/ +//g' |
awk -v cn=$cn -F'\t' 'NR<3 || $cn == "" {next} {print $cn}' |
while read wday; do
echo $year/$month/$wday
done
outputs:
2021/8/4
2021/8/11
2021/8/18
2021/8/25
Without using cal or ncal...
#!/bin/bash
inputDate="2021/08/25"
dow=$(date -d "$inputDate" +"%a")
month=$(date -d "$inputDate" +"%m")
outputDates=""
for x in $(seq 0 9)
do
validDate=$(date -d "$x $dow 5 week ago" +"%Y/%m/%d" | grep "/$month/")
if [ ! -z $validDate ]
then
if [ ! -z $outputDates ]
then
outputDates="$outputDates,$validDate"
else
outputDates="$validDate"
fi
fi
done
echo "$outputDates"
This script outputs:
2021/08/04,2021/08/11,2021/08/18,2021/08/25

Parsing cal output in POSIX compliant shell script by read command

I am trying to write a POSIX compliant script, which will print all months in specified year $3, that have day in $1 (for example Mo, Tu,...) on a same date as $2 (1,2,3,...).
Example:
Input: ./task1.sh Tu 5 2006
Output:
September 2006
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30
December 2006
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
I have written this script:
#!/bin/sh
year=$3
dayInMonth=$2
dayInWeek=$1
index=1
while expr $index '!=' 13 >/dev/null; do
cal -m $index $year| tail -n +2| while read Mo Tu We Th Fr Sa Su ; do
eval theDay='$'$dayInWeek
if [ "$theDay" = "$dayInMonth" ]; then
cal -m $index $year;
fi
done
index=$(expr $index + 1)
done
But there is a problem with reading of third line of cal output. In these lines numbers of days usually don't start at Mo place. How can I parse third line of cal output so the numbers in $Mo, $Tu, $We,... are always correct?
Update: You've added the requirement for a posix conform solution. date -d as used in my answer is not POSIX conform. I'll keep the answer for those who are using GNU/Linux.
Btw, the following command gives you posixly correct the day of week offset of Jan 5, 2006:
cal 01 2006 | awk -v d=5 'NR>2{for(i=1;i<NF;i++){if($i==d){print i;exit}}}'
You need to tinker a little shell script around that.
I would use the date command, like this:
#!/bin/bash
dayofweek="${1}"
day="${2}"
year="${3}"
for m in {01..12} ; do
date=$(LANG=C date -d "${year}-${m}-${day}" +'%a %B')
read d m <<< "${date}"
[ "${d}" = "${dayofweek}" ] && echo "${m}"
done
Results:
$ bash script.sh Thu 05 2006
January
October
It's easier to check dates with the command date.
for month in {1..12}; do
if [[ $(date -d $(printf "%s-%2.2d-%2.2d" "$year" "$month" "$day") "+%a") == "Tue" ]]; then
cal -m $month $year;
fi
done
The script loops over the 12 months and generate a date based on year and day. The date command outputs the day of the in a 3 letters format with +%a.
If you want the day of week in number format, use +%u and == 2 in the if statement.

How to convert timestamp to hour/minutes/seconds in shell script?

I am calculating how much time my code is taking in shell script -
date1=$(date +"%s")
# some code here
date2=$(date +"%s")
diff=$(($date2-$date1))
echo "Time Taken - $(($diff / 60)) minutes and $(($diff % 60)) seconds elapsed."
Above script prints out time taken in minutes and seconds. How can I add it for hours as well? Meaning it should print out Time Taken - 0 hours 54 minutes 0 seconds something like this.
Try this:
echo "Time Taken - $((diff /60/60)) hours and $(($diff % 60)) minutes and $(($diff % 60)) seconds elapsed."
if you're starting with integer seconds that all fall within a single day, and only need HH:MM:SS, here's a very strange way to use jot + bc :
jot -w 'obase = 60; ' - 91 86400 9091 | bc
01 31
02 33 02
05 04 33
07 36 04
10 07 35
12 39 06
15 10 37
17 42 08
20 13 39
22 45 10

Bash format uptime to show days, hours, minutes

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.
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."
}'
Just vor completeness... what's about:
$ uptime -p
up 2 weeks, 3 days, 14 hours, 27 minutes
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.
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"
Gist
Referenced John1024 answer with my own customizations.
For this:
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
More simple is:
uptime -p | cut -d " " -f2-
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.
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 ]
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
}

Resources