feat(user/bkots):Execute via array elements, not string concat
[BK-2020-03.git] / unitproc / bkuptime
1 #!/bin/bash
2 # Desc: Displays `uptime` information but with ISO-8601 time period
3 # string.
4
5 yell() { echo "$0: $*" >&2; } # Yell, Die, Try Three-Fingered Claw technique; # Ref/Attrib: https://stackoverflow.com/a/25515370
6 die() { yell "$*"; exit 111; }
7 try() { "$@" || die "cannot $*"; }
8 timeDuration(){
9 # Desc: Given seconds, output ISO-8601 duration string
10 # Ref/Attrib: ISO-8601:2004(E), §4.4.4.2 Representations of time intervals by duration and context information
11 # Note: "1 month" ("P1M") is assumed to be "30 days" (see ISO-8601:2004(E), §2.2.1.2)
12 # Usage: timeDuration [1:seconds] ([2:precision])
13 # Version: 1.0.5
14 # Input: arg1: seconds as base 10 integer >= 0 (ex: 3601)
15 # arg2: precision level (optional; default=2)
16 # Output: stdout: ISO-8601 duration string (ex: "P1H1S", "P2Y10M15DT10H30M20S")
17 # exit code 0: success
18 # exit code 1: error_input
19 # exit code 2: error_unknown
20 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
21 # Depends: date 8, bash 5, yell,
22 local argSeconds argPrecision precision returnState remainder
23 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
24 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
25 local witherPrecision output
26 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
27
28 argSeconds="$1"; # read arg1 (seconds)
29 argPrecision="$2"; # read arg2 (precision)
30 precision=2; # set default precision
31
32 # Check that between one and two arguments is supplied
33 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
34 yell "ERROR:Invalid number of arguments:$# . Exiting.";
35 returnState="error_input"; fi
36
37 # Check that argSeconds provided
38 if [[ $# -ge 1 ]]; then
39 ## Check that argSeconds is a positive integer
40 if [[ "$argSeconds" =~ ^[[:digit:]]+$ ]]; then
41 :
42 else
43 yell "ERROR:argSeconds not a digit.";
44 returnState="error_input";
45 fi
46 else
47 yell "ERROR:No argument provided. Exiting.";
48 exit 1;
49 fi
50
51 # Consider whether argPrecision was provided
52 if [[ $# -eq 2 ]]; then
53 # Check that argPrecision is a positive integer
54 if [[ "$argPrecision" =~ ^[[:digit:]]+$ ]] && [[ "$argPrecision" -gt 0 ]]; then
55 precision="$argPrecision";
56 else
57 yell "ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
58 returnState="error_input";
59 fi;
60 else
61 :
62 fi;
63
64 remainder="$argSeconds" ; # seconds
65 ## Calculate full years Y, update remainder
66 fullYears=$(( remainder / (365*24*60*60) ));
67 remainder=$(( remainder - (fullYears*365*24*60*60) ));
68 ## Calculate full months M, update remainder
69 fullMonths=$(( remainder / (30*24*60*60) ));
70 remainder=$(( remainder - (fullMonths*30*24*60*60) ));
71 ## Calculate full days D, update remainder
72 fullDays=$(( remainder / (24*60*60) ));
73 remainder=$(( remainder - (fullDays*24*60*60) ));
74 ## Calculate full hours H, update remainder
75 fullHours=$(( remainder / (60*60) ));
76 remainder=$(( remainder - (fullHours*60*60) ));
77 ## Calculate full minutes M, update remainder
78 fullMinutes=$(( remainder / (60) ));
79 remainder=$(( remainder - (fullMinutes*60) ));
80 ## Calculate full seconds S, update remainder
81 fullSeconds=$(( remainder / (1) ));
82 remainder=$(( remainder - (remainder*1) ));
83 ## Check which fields filled
84 if [[ $fullYears -gt 0 ]]; then hasYears="true"; else hasYears="false"; fi
85 if [[ $fullMonths -gt 0 ]]; then hasMonths="true"; else hasMonths="false"; fi
86 if [[ $fullDays -gt 0 ]]; then hasDays="true"; else hasDays="false"; fi
87 if [[ $fullHours -gt 0 ]]; then hasHours="true"; else hasHours="false"; fi
88 if [[ $fullMinutes -gt 0 ]]; then hasMinutes="true"; else hasMinutes="false"; fi
89 if [[ $fullSeconds -ge 0 ]]; then hasSeconds="true"; else hasSeconds="false"; fi
90
91 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
92 witherPrecision="false"
93
94 ### Years
95 if $hasYears && [[ $precision -gt 0 ]]; then
96 displayYears="true";
97 witherPrecision="true";
98 else
99 displayYears="false";
100 fi;
101 if $witherPrecision; then ((precision--)); fi;
102
103 ### Months
104 if $hasMonths && [[ $precision -gt 0 ]]; then
105 displayMonths="true";
106 witherPrecision="true";
107 else
108 displayMonths="false";
109 fi;
110 if $witherPrecision && [[ $precision -gt 0 ]]; then
111 displayMonths="true";
112 fi;
113 if $witherPrecision; then ((precision--)); fi;
114
115 ### Days
116 if $hasDays && [[ $precision -gt 0 ]]; then
117 displayDays="true";
118 witherPrecision="true";
119 else
120 displayDays="false";
121 fi;
122 if $witherPrecision && [[ $precision -gt 0 ]]; then
123 displayDays="true";
124 fi;
125 if $witherPrecision; then ((precision--)); fi;
126
127 ### Hours
128 if $hasHours && [[ $precision -gt 0 ]]; then
129 displayHours="true";
130 witherPrecision="true";
131 else
132 displayHours="false";
133 fi;
134 if $witherPrecision && [[ $precision -gt 0 ]]; then
135 displayHours="true";
136 fi;
137 if $witherPrecision; then ((precision--)); fi;
138
139 ### Minutes
140 if $hasMinutes && [[ $precision -gt 0 ]]; then
141 displayMinutes="true";
142 witherPrecision="true";
143 else
144 displayMinutes="false";
145 fi;
146 if $witherPrecision && [[ $precision -gt 0 ]]; then
147 displayMinutes="true";
148 fi;
149 if $witherPrecision; then ((precision--)); fi;
150
151 ### Seconds
152
153 if $hasSeconds && [[ $precision -gt 0 ]]; then
154 displaySeconds="true";
155 witherPrecision="true";
156 else
157 displaySeconds="false";
158 fi;
159 if $witherPrecision && [[ $precision -gt 0 ]]; then
160 displaySeconds="true";
161 fi;
162 if $witherPrecision; then ((precision--)); fi;
163
164 ## Determine whether or not the "T" separator is needed to separate date and time elements
165 if ( $displayHours || $displayMinutes || $displaySeconds); then
166 displayDateTime="true"; else displayDateTime="false"; fi
167
168 ## Construct duration output string
169 output="P"
170 if $displayYears; then
171 output=$output$fullYears"Y"; fi
172 if $displayMonths; then
173 output=$output$fullMonths"M"; fi
174 if $displayDays; then
175 output=$output$fullDays"D"; fi
176 if $displayDateTime; then
177 output=$output"T"; fi
178 if $displayHours; then
179 output=$output$fullHours"H"; fi
180 if $displayMinutes; then
181 output=$output$fullMinutes"M"; fi
182 if $displaySeconds; then
183 output=$output$fullSeconds"S"; fi
184
185 ## Output duration string to stdout
186 echo "$output" && returnState="true";
187
188 #===Determine function return code===
189 if [ "$returnState" = "true" ]; then
190 return 0;
191 elif [ "$returnState" = "error_input" ]; then
192 yell "ERROR:input";
193 return 1;
194 else
195 yell "ERROR:Unknown";
196 return 2;
197 fi
198
199 } # Get duration (ex: PT10M4S )
200 uptimeIso8601() {
201 # Desc: Get system uptime with ISO_8601-formatted time period
202 # Usage: uptimeIso8601
203 # Output: A string similar to `uptime` but with date and uptime
204 # time period replaced with a period/endtime ISO-8601-formatted
205 # string.
206 # ex: `P3DT23H36M46S/2021-03-28T14:47:48+0000, 5 users, load average: 0.09, 0.10, 0.13`
207 # Note: No arguments used.
208 # Depends: timeDuration() v1.0.5, uptime
209 # Version: 0.0.1
210 # Ref/Attrib: get uptime in seconds https://leo.leung.xyz/wiki/Linux_Uptime_in_Seconds
211 sysUptime=$(</proc/uptime);
212 sysUptime=${sysUptime%%.*}; #
213 sysUptimeIso="$(timeDuration $sysUptime 4)";
214 timeNow="$(date +%Y-%m-%dT%H:%M:%S%z)";
215 users_load="$(uptime | cut -d',' -f3-)";
216 output="$sysUptimeIso"/"$timeNow","$users_load ";
217 echo "$output";
218 } # Get uptime with ISO-8601 time period
219 main() {
220 uptimeIso8601;
221 }
222
223 main;
224 # Author: Steven Baltakatei Sandoval
225 # License: GPLv3+