Reputation: 20384
I have a file like this that contains multiple fields in lines. I want to display some of them, while processing one of them with another command.
TITLE,OpenVPN ...
HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Virtual IPv6 Address,Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username,Client ID,Peer ID
CLIENT_LIST,name1,1.1.1.1:1,10.0.0.1,,2692253,3765861,Wed Jun 23 12:51:08 2021,1624452668,name1,4727,0
CLIENT_LIST,name2,2.2.2.2:2,10.0.0.2,,1571221,2080242,Thu Jul 1 19:24:10 2021,1625167450,name2,5625,0
CLIENT_LIST,name3,3.3.3.3:3,10.0.0.3,,2670410,3736957,Wed Jun 23 16:20:51 2021,1624465251,name3,4747,0
...
The expected output is this:
name1 10.0.0.1 2021-06-23 12:51:08
name2 10.0.0.2 2021-07-01 19:24:10
name3 10.0.0.3 2021-06-23 16:20:51
The command I have now is this:
grep '^CLIENT_LIST,' /var/run/ovpn-server.status |awk -F',' '{print $2 $4 $9}' |sort
It prints the desired fields, but doesn't convert the timestamp to a formatted time. Here's the command for that:
date -d @1624452668 +"%Y-%m-%d %H:%M:%S"
How can I integrate the date
command into the awk
script? Or what other solution is there to accomplish this?
I also intend to put the output into a columns/table layout with the column
command, I've done that before, so that's not part of the question.
Upvotes: 1
Views: 133
Reputation: 785216
You may use this awk
:
awk -F, -v OFS='\t' '$1 == "CLIENT_LIST" {
cmd = "date +\047%Y-%m-%d %H:%M:%S\047 -d\047@" $9 "\047"
print $2, $4, ((cmd | getline dt) > 0 ? dt : $9)
close(dt)
}' file
name1 10.0.0.1 2021-06-23 08:51:08
name2 10.0.0.2 2021-07-01 15:24:10
name3 10.0.0.3 2021-06-23 12:20:51
Explanation:
-F, -v OFS='\t'
: Sets input field separator as ,
and output field separator as tab'$1 == "CLIENT_LIST"
: Do it when first field is CLIENT_LIST
cmd = "date +\047%Y-%m-%d %H:%M:%S\047 -d\047@" $9 "\047"
: Format date
command using $9
cmd | getline dt
invokes external date
command(cmd | getline dt) > 0
: When date
command is a successprint
: prints 2nd, 4th and output of date
fieldUpvotes: 5
Reputation: 203645
If you actually just want the date+time from $8
reformatted instead of converting the seconds since the epoch from $9
to a date+time then you can just do the following which will be orders of magnitude faster than calling date
since that would require awk
to spawn a subshell once per input line to call date
from that subshell which would be extremely slow.
Using any awk in any shell on every Unix box:
$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
NR > 2 {
split($8,t," ")
mthNr = (index("JanFebMarAprMayJunJulAugSepOctNovDec",t[2])+2)/3
print $2, $4, sprintf("%04d-%02d-%02d %s", t[5], mthNr, t[3], t[4])
}
$ awk -f tst.awk file
name1 10.0.0.1 2021-06-23 12:51:08
name2 10.0.0.2 2021-07-01 19:24:10
name3 10.0.0.3 2021-06-23 16:20:51
or if you really want to use the epoch seconds from $9 then use GNU awk for strftime()
so you don't have to spawn subshells to call date
(but note that the output now becomes TZ-dependent, just like with date
):
$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
NR > 2 {
print $2, $4, strftime("%F %T",$9)
}
$ awk -f tst.awk file
name1 10.0.0.1 2021-06-23 07:51:08
name2 10.0.0.2 2021-07-01 14:24:10
name3 10.0.0.3 2021-06-23 11:20:51
$ TZ=UTC awk -f tst.awk file
name1 10.0.0.1 2021-06-23 12:51:08
name2 10.0.0.2 2021-07-01 19:24:10
name3 10.0.0.3 2021-06-23 16:20:51
or setting the UTC flag in strftime() if UTC is what you have in your data:
$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
NR > 2 {
print $2, $4, strftime("%F %T",$9,1)
}
$ awk -f tst.awk file
name1 10.0.0.1 2021-06-23 12:51:08
name2 10.0.0.2 2021-07-01 19:24:10
name3 10.0.0.3 2021-06-23 16:20:51
Upvotes: 1