/proc/uptime in Mac OS X - macos

I need the EXACT same output as Linux's "cat /proc/uptime".
For example, with /proc/uptime, you'd get
1884371.64 38646169.12
but with any Mac alternative, like "uptime", you'd get
20:25 up 20:26, 6 users, load averages: 3.19 2.82 2.76
I need it to be exactly like cat /proc/uptime, but on Mac OS X.

Got it...
$sysctl -n kern.boottime | cut -c14-18
87988
Then I just converted that to readable format (don't remember how):
1 Days 00:26:28

There simply is no "/proc" directory on the Macintosh.
On MacOS, you can do a command like:
sysctl kern.boottime
and you'll get a response like:
kern.boottime: { sec = 1362633455, usec = 0 } Wed Mar 6 21:17:35 2013

boottime=`sysctl -n kern.boottime | awk '{print $4}' | sed 's/,//g'`
unixtime=`date +%s`
timeAgo=$(($unixtime - $boottime))
uptime=`awk -v time=$timeAgo 'BEGIN { seconds = time % 60; minutes = int(time / 60 % 60); hours = int(time / 60 / 60 % 24); days = int(time / 60 / 60 / 24); printf("%.0f days, %.0f hours, %.0f minutes, %.0f seconds", days, hours, minutes, seconds); exit }'`
echo $uptime
Will return something like
1 Day, 20 hours, 10 minutes, 55 seconds

Here is what I Do to get the the values instead of Cut method
sysctl kern.boottime | awk '{print $5}'
Where $5 is the Range of the string
Example
$1 Gives you "sysctl kern.boottime"
$2 Gives you "{"
$3 Gives you "sec"
from the String
kern.boottime: { sec = 1604030189, usec = 263821 } Fri Oct 30 09:26:29 2020

Related

create a list of date and time in shell script

I try to run script to find the missing dates in a file "date_meta", therefore I try to write a list of whole dates using shell script and put it in file "date_correct". The format is %d%H%M with increment of 30 minutes. I get this error: line 9: [[: 2022-01-01T00: value too great for base (error token is "01T00")
The script:
#!/bin/sh
strdate='2022-01-01T00:00'
enddate='2022-01-31T23:30'
while [[ ${strdate} -le ${enddate} ]] ; do
echo $strdate>>date_correct
strdate=$(date -d "$strdate 30 minute" +%d%H%M)
done
diff date_metar date_correct >output
Your best bet for generating the range of valid dates/times will probably come from combining two ideas:
use epoch seconds for comparisons and math
use awk (or comparable program) to replace the time-consuming bash/while loop
One epoch(secs) / awk idea:
strdate='2022-01-01T00:00'
enddate='2022-01-31T23:30'
strdate_s=$(date -d "${strdate}" +%s)
enddate_s=$(date -d "${enddate}" +%s)
inc_m=30
((inc_s = inc_m * 60))
awk -v ss="${strdate_s}" -v es="${enddate_s}" -v inc="${inc_s}" '
BEGIN { while ( ss <= es ) {
print strftime("%d%H%M", ss)
ss+=inc
}
}
' > date_correct
NOTE: as Fravadona's mentioned in the comments, strftime() requires GNU awk (aka gawk)
To show the performance improvement of using awk instead of the bash/while loop we'll modify OP's current code to use the epoch(secs) approach:
strdate='2022-01-01T00:00'
enddate='2022-01-31T23:30'
strdate_s=$(date -d "${strdate}" +%s)
enddate_s=$(date -d "${enddate}" +%s)
inc_m=30
((inc_s = inc_m * 60))
while [[ "${strdate_s}" -le "${enddate_s}" ]] ; do
date -d "#${strdate_s}" +%d%H%M >> date_correct2
((strdate_s+=inc_s))
done
A diff of the outputs show both sets of code generate the same output:
$ diff date_correct date_correct2
<<<=== no output
Results of running both processes under time:
# awk
real 0m0.042s
user 0m0.015s
sys 0m0.015s
# bash/while
real 0m46.412s
user 0m6.727s
sys 0m27.314s
So awk is about 1100x times faster than a comparable bash/while loop.
If the sole purpose of this date/time-generating code is simply to find the missing dates/times in the date_metar file then OP may want to consider using a single awk script to eliminate the need for the date_correct file and still determine what dates/times are missing from date_metar ... but that's for another Q&A ...
Looking a bit more into the performance issues of the bash/while loop ...
Replacing the date call with a comparable printf -v call:
while [[ "${strdate_s}" -le "${enddate_s}" ]] ; do
printf -v new_date '%(%d%H%M)T' "${strdate_s}"
echo "${new_date}" >> date_correct2
((strdate_s+=inc_s))
done
We see overall time is reduced from 46+ secs to 10+ secs:
real 0m10.127s
user 0m0.141s
sys 0m0.312s
We should be able to get a further improvement by moving the >> date_correct2 to after the done, thus replacing 1400+ file open/close operations (date ... >> date_correct2) with a single file open/close operation (done > date_correct2)
while [[ "${strdate_s}" -le "${enddate_s}" ]] ; do
printf -v new_date '%(%d%H%M)T' "${strdate_s}"
echo "${new_date}"
((strdate_s+=inc_s))
done > date_correct2
This speeds up the process by ~50x times (10+ secs down to 0.2 secs):
real 0m0.198s
user 0m0.141s
sys 0m0.000s
Thus reducing the bash/while loop overhead (compared to awk) from 1100x to 5x.
strftime() does not require gnu-awk ::: gawk
mawk1 'BEGIN { fmt = "%Y-%m-%d %H:%M:%S %Z ( epochs %s | %Y-%j )"
print ORS, systime(), ORS ORS, strftime(fmt, systime()), ORS }'
1662840559
2022-09-10 16:09:19 EDT ( epochs 1662840559 | 2022-253 )
you'll get a very tiny, almost statistically insignificant, speed gain via mawk-1 :
{m,g}awk -v __='2022 01 01 00 00 00' \
-v ___='2022 01 31 23 30 00' '
BEGIN { _*= (_+=(_+=(_^=_<_)+_)^_)+_
__ = mktime(__)
___ = mktime(___)
____ = "%Y-%m-%d %H:%M:%S %Z ( %s | %Y-%j )"
do {
print __, strftime(____,__) } while ((__+=_)<=___) }'
out9: 78.5KiB 0:00:00 [64.4MiB/s] [64.4MiB/s] [<=> ]
( mawk -v __='2022 01 01 00 00 00' -v ___='2022 01 31 23 30 00' -- ; )
0.01s user 0.00s system 89% cpu 0.019 total
1484 1643682600 2022-01-31 21:30:00 EST ( 1643682600 | 2022-031 )
1485 1643684400 2022-01-31 22:00:00 EST ( 1643684400 | 2022-031 )
1486 1643686200 2022-01-31 22:30:00 EST ( 1643686200 | 2022-031 )
1487 1643688000 2022-01-31 23:00:00 EST ( 1643688000 | 2022-031 )
1488 1643689800 2022-01-31 23:30:00 EST ( 1643689800 | 2022-031 )
|
out9: 78.5KiB 0:00:00 [17.0MiB/s] [17.0MiB/s] [<=> ]
( gawk -v __='2022 01 01 00 00 00' -v ___='2022 01 31 23 30 00' -be ; )
0.02s user 0.01s system 85% cpu 0.026 total
1484 1643682600 2022-01-31 21:30:00 EST ( 1643682600 | 2022-031 )
1485 1643684400 2022-01-31 22:00:00 EST ( 1643684400 | 2022-031 )
1486 1643686200 2022-01-31 22:30:00 EST ( 1643686200 | 2022-031 )
1487 1643688000 2022-01-31 23:00:00 EST ( 1643688000 | 2022-031 )
1488 1643689800 2022-01-31 23:30:00 EST ( 1643689800 | 2022-031 )

Unix converting time format to integer value

I have the following text file.
Account1,2h 01m 00s
Account2,4h 25m 23s
Account3,5h 43m 59s
I wish to add the values of hours, minutes and seconds in order to total them to their respective minute totals.
Account1 minute total = 121
Account2 minute total = 265
Account3 minute total = 343
I have the following bash file
cat data.txt | cut -f2 -d','
This isolates the time values; however, from here I don't know what steps I would take to isolate the time, convert it to integers and then convert it to minutes. I have tried using a PARAM but to no avail.
If awk is an option, you can try this
awk -F"[, ]" '{h=60; m=1; s=0.01666667}{split($2,a,/h/); split($3,b,/m/); split($4,c,/s/); print$1, "minute total = " int(a[1] * h + b[1] * m + c[1] * s)}' input_file
$ cat awk.script
BEGIN {
FS=",| "
} {
h=60
m=1
s=0.01666667
}{
split($2,a,/h/)
split($3,b,/m/)
split($4,c,/s/)
print $1, "minute total = " int(a[1] * h + b[1] * m + c[1] * s)
}
Output
awk -f awk.script input_file
Account1 minute total = 121
Account2 minute total = 265
Account3 minute total = 343

how to calculate total elapsed time

how to calculate elapsed time based on
start time=
[user001a#dev51 logs]# grep 'Recovery Manager'
refresh_03Jun2019_0250.log|head -1|awk -F'on ' '{print $NF}';
Jun 3 02:50:02 2019
[user001a#dev51 logs]#
end time=
[user001a#dev51 logs]# ls -l refresh_03Jun2019_0250.log
-rw-r--r--. 1 user001a grp001a 170050 Jun 3 05:06
refresh_03Jun2019_0250.log
[user001a#dev51 logs]#
Note - stat is missing birth time so stat might not be a good option time calculate file create and modify time:
[user001a#dev51 logs]# stat refresh_03Jun2019_0250.log
File: `refresh_03Jun2019_0250.log'
Size: 170050 Blocks: 344 IO Block: 4096 regular file
Device: 811h/2065d Inode: 1474545 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 219/ user001a) Gid: ( 219/grp001a)
Access: 2019-06-03 05:06:40.830829026 -0400
Modify: 2019-06-03 05:06:40.827828883 -0400
Change: 2019-06-03 05:06:40.827828883 -0400
[user001a#dev51 logs]#
Sample1 output:
StartTime=June 3, 2019 at 2:50:02 am
EndTime=June 3, 2019 at 5:06:40 am
ElapsedTime=2 hours, 16 minutes and 38 seconds
Sample2 output:
ElapsedTime=2 hours, 16 minutes and 38 seconds
Limitation of this solution: Max 23 hours. For more, days need to be added.
StartTime="June 3, 2019 at 2:50:02 am"
EndTime="June 3, 2019 at 5:06:40 am"
StartTimeInEpoch=`echo $StartTime | sed 's/at //g' | date -f- +"%s"`
EndTimeInEpoch=`echo $EndTime | sed 's/at //g' | date -f- +"%s"`
echo $EndTimeInEpoch-$StartTimeInEpoch | bc | sed 's/^/#/g' | date -u -f- "+%_H hours %_M minutes %_S seconds"
Output:
2 hours 16 minutes 38 seconds
Assuming you've got your dates in variables StartTime and EndTime. It's necessary to remove at from them, sed do this. Then both dates are converted to epoch time +"%s" do the trick. -f- tells date to take date from stdin (pipe). Then we can subtract the dates, add # to the beginning and format with date. -u mean UTC time - no time shift.

Nested getline in AWK script

Please let me know if we can use nested getline within AWK scripts like:
while ( ("tail -f log" |& getline var0) > 0) {
while ( ("ls" | getline ) > 0) {
}
close("ls")
while ( ("date" | getline ) > 0) {
}
close("date")
}
close("tail -f log")
What is the depth we can make use of nested getline functionality and will there be any data loss of output at any level of the nested getline? What are the things we should make sure in implementing this style?
==================================================================================
UPDATE===================UPDATE==============UPDATE===============UPDATE=======
Requirement : Provide real time statistical data and errors by probing QA box and webserver / services logs and system status. Report would be generated in following format:
Local Date And Time | Category| Component | Condition
Assumption -: AWK script would execute faster than shell script with added advantage of using its inbuilt parsing and other functionalities.
Implementation : - The main command loop is command0="tail -f -n 0 -s 5 ...........". This command would start an infinite loop extracting appended logs of services / webserver of QA box. . Note the -f, -s and –n options which makes to dump all appended data to logs, sleep for 5 seconds after each iterations and start without printing any default content from the existing logs.
After each iteration, capture and verify the system time and execute various OS resource commands after 10 seconds interval (5 seconds sleep in-between each iteration and 4 seconds after processing the tail output – assuming that processing all tail command roughly take 1 sec, hence in all 10 seconds)
Various command I have used for extracting OS resources are:
I. command1="vmstat | nl | tr -s '\\t '"
II. command2="sar -W 0"
III. command3="top -b -n 1 | nl | tr -s '\\t '"
IV. command4="ls -1 /tmp | grep EXIT"
Search for respective command(?) in the script and go thru the while loop of it in the script to figure output processing of the respective command. Note I nave used ‘nl’ command for development / coding ease
Ultimately presence of /tmp/EXIT file on the box will make the script to exit after removing the same from the box
Below is my script - I have added comments as much as possible for self explanatory:
#Useage - awk -f script.awk
BEGIN {
command0="tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log"
command1="vmstat | nl | tr -s '\\t '"
command2="sar -W 0"
command3="top -b -n 1 | nl | tr -s '\\t '"
command4="ls -1 /tmp | grep EXIT"
format = "%a %b %e %H:%M:%S %Z %Y"
split("", details)
split("", fields)
split("", data)
split("", values)
start_time=0
printf "\n>%s:\n\n", command0 #dummy print for debuggng command being executed
while ( (command0 |& getline var0) > 0) { #get the command output
if (start_time == 0) #if block to reset the start_time variable
{
start_time = systime() + 4
}
if (var0 ~ /==>.*<==/) { #if block to extract the file name from the tail output - outputted in '==>FileName<==' format
gsub(/[=><]/, "", var0)
len = split(var0, name, "/")
if(len == 7) {file = name[5]} else {file = name[6]}
}
if (len == 7 && var0 ~ /[Ee]rror|[Ee]xception|ORA|[Ff]atal/) { #extract the logs error statements
print strftime(format,systime()) " | Error Log | " file " | Error :" var0
}
if(systime() >= start_time) #check if curernt system time is greater than start_time as computed above
{
start_time = 0 #reset the start_time variable and now execute the system resource command
printf "\n>%s:\n\n", command1
while ( (command1 |& getline) > 0) { #process output of first command
if($1 <= 1)
continue #not needed for processing skip this one
if($1 == 2) #capture the fieds name and skip to next line
{
for (i = 1; i <= NF; i++){fields[$i] = i;}
continue
}
if ($1 == 3) #store the command data output in data array
split($0, data);
print strftime(format,systime()) " | System Resource | System | Time spent running non-kernel code :" data[fields["us"]]
print strftime(format,systime()) " | System Resource | System | Time spent running kernel code :" data[fields["sy"]]
print strftime(format,systime()) " | System Resource | System | Amount of memory swapped in from disk :" data[fields["si"]]
print strftime(format,systime()) " | System Resource | System | Amount of memory swapped to disk :" data[fields["so"]]
}
close(command1)
printf "\n>%s:\n\n", command2 #start processing second command
while ( (command2 |& getline) > 0) {
if ($4 ~ /[0-9]+[\.][0-9]+/) #check for 4th positional value if its format is of "int.intint" format
{
if( $4 > 0.0) #dummy check now to print if page swapping
print strftime(format,systime()) " | System Resource | Disk | Page rate is > 0.0 reads/second: " $4
}
}
close(command2)
printf "\n>%s:\n\n", command3 # start processing command number 3
while ( (command3 |& getline ) > 0) {
if($1 == 1 && $0 ~ /load average:/) #get the load average from the output if this is the first line
{
split($0, arr, ",")
print strftime(format,systime())" | System Resource | System |" arr[4]
}
if($1 > 7 && $1 <= 12) # print first top 5 process that are consuming most of the CPUs time
{
f=split($0, arr, " ")
if(f == 13)
print strftime(format,systime())" | System Resource | System | CPU% "arr[10]" Process No: "arr[1] - 7" Name: "arr[13]
}
}
close(command3)
printf "\n>%s:\n\n", command4 #process command number 4 to check presence of file
while ( (command4 |& getline var4) > 0) {
system("rm -rf /tmp/EXIT")
exit 0 #if file is there then remove the file and exit this script execution
}
close(command4)
}
}
close(command0)
}
Output -:
>tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log:
>vmstat | nl | tr -s '\t ':
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Time spent running non-kernel code :9
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Time spent running kernel code :9
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Amount of memory swapped in from disk :0
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Amount of memory swapped to disk :2
>sar -W 0:
Sun Dec 16 23:05:12 PST 2012 | System Resource | Disk | Page rate is > 0.0 reads/second: 3.89
>top -b -n 1 | nl | tr -s '\t ':
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | load average: 3.63
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 12.0 Process No: 1 Name: occworker
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 10.3 Process No: 2 Name: occworker
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 3 Name: caldaemon
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 4 Name: occmux
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 5 Name: top
>ls -1 /tmp | grep EXIT:
This is your second post that I can recall about using getline this way. I mentioned last time that it was the wrong approach but it looks like you didn't believe me so let me try one more time.
Your question of "how do I use awk to execute commands with getline to read their output?" is like asking "how do I use a drill to cut glass?". You could get an answer telling you to tape over the part of the glass where you'll be drilling to avoid fracturing it and that WOULD answer your question but the more useful answer would probably be - don't do that, use a glass cutter.
Using awk as a shell from which to call commands is 100% the wrong approach. Simply use the right tool for the right job. If you need to parse a text file, use awk. If you need to manipulate files or processes or invoke commands, use shell (or your OS equivalent).
Finally, please read http://awk.freeshell.org/AllAboutGetline and don't even think about using getline until you fully understand all the caveats.
EDIT: here's a shell script to do what your posted awk script does:
tail -f log |
while IFS= read -r var0; do
ls
date
done
Look simpler? Not saying it makes sense to do that, but if you did want to do it, THAT's the way to implement it, not in awk.
EDIT: here's how to write the first part of your awk script in shell (bash in this case), I ran out of enthusiasm for translating the rest of it for you and I think this shows you how to do the rest yourself:
format = "%a %b %e %H:%M:%S %Z %Y"
start_time=0
tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log |
while IFS= read -r line; do
systime=$(date +"%s")
#block to reset the start_time variable
if ((start_time == 0)); then
start_time=(( systime + 4 ))
fi
#block to extract the file name from the tail output - outputted in '==>FileName<==' format
case $var0 in
"==>"*"<==" )
path="${var0%% <==}"
path="${path##==> }"
name=( ${path//\// } )
len="${#name[#]}"
if ((len == 7)); then
file=name[4]
else
file=name[5]
fi
;;
esac
if ((len == 7)); then
case $var0 in
[Ee]rror|[Ee]xception|ORA|[Ff]atal ) #extract the logs error statements
printf "%s | Error Log | %s | Error :%s\n" "$(date +"$format")" "$file" "$var0"
;;
esac
fi
#check if curernt system time is greater than start_time as computed above
if (( systime >= start_time )); then
start_time=0 #reset the start_time variable and now execute the system resource command
....
Note that this would execute slightly faster than your awk script but that absolutely does not matter at all since your tail is taking 5 second breaks between iterations.
Also note that all I'm doing above is translating your awk script into shell, it doesn't necessarily mean it'd be the best way to write this tool from scratch.

How can i switch place of hour and minutes from a clock command (for crontab) using awk

I want to use a command to make a crontab that plays an alarm (for my wife). The program is called ipraytime and it gives an output like this.
$ ipraytime -u +2
Prayer schedule for,
City : Custom
Latitude : 021�� 25' 12" N
Longitude : 039�� 49' 47" E
Angle Method : Umm Al-Qurra University
TimeZone : UTC+2.0
Qibla : 061�� 45' 42" W of true North
Date Fajr Shorooq Zuhr Asr Maghrib Isha
--------------------------------------------------------------------
[09-05-2012] 4:19 5:43 12:16 15:35 18:48 20:18
Today's Imsaak : 4:11
Tomorrow's Imsaak : 4:10
Tomorrow's Fajr : 4:18
What i want is that the times format good for a crontab which means i need to switch places of the minute and hour. To be 19 4 instead.
I have made this command but don't know how to make that switch.
ipraytime -u +2| awk 'NR==12 {print $2"\n"$3"\n"$4"\n"$5"\n"$6"\n"$7}' | sed 's/:/ /g'
This gives me an output like this
4 19
5 43
12 16
15 35
18 48
20 18
But i want it to be like this
19 4
43 5
16 12
35 15
48 18
18 20
As that is what a crontab is using. I have played with sort a bit but couldn't find a solution there either.
(Sorry for the bad topic.. didn't know how to write a good one for this)
It's not necessary to use sed at all.
$ ipraytime -u +2 | awk -F ' +|:' 'NR == 12 {for (i = 2; i <= 12; i += 2) print $(i+1), $i}'
19 4
43 5
16 12
35 15
48 18
18 20
Use sed 's/\(.*\):\(.*\)/\2 \1/'
Command:
ipraytime -u +2 | awk 'NR==12 {print $2"\n"$3"\n"$4"\n"$5"\n"$6"\n"$7}'
| sed 's/\(.*\):\(.*\)/\2 \1/'

Resources