3 remarks:
.1 about bash
As this question is tagged bash and no answer here address printf
bashism:
Syntax: printf '%(fmt)T' $UNIXEPOCH
Under bash, from V4.2, (Feb 2011), The printf builtin has a %(fmt)T
specifier, which allows time values to use strftime-like formatting.
TZ=UTC LANG=C printf '%(%A %d %b %Y, %T %Z)T\n' 12345678
Saturday 23 May 1970, 21:21:18 UTC
Used without argument or with -1
as argument, this will print current time:
printf '%(%b %d, %T)T\n'
Aug 03, 08:42:28
As printf
repeat format sequenc for as many argument present in command line:
$ TZ=UTC LANG=C printf '%(%A %d %b %Y, %T %Z)T\n' -1 123456789 $EPOCHSECONDS
Sunday 20 Nov 2022, 13:04:42 UTC
Thursday 29 Nov 1973, 21:33:09 UTC
Sunday 20 Nov 2022, 13:04:42 UTC
Without argument and without fmt
string, printf '%()T'
will print current time:
printf '%()T\n'
12:34:56
echo $(( $(TZ=UTC printf "%()T" | sed 's/:/* 3600 +/;s/:/* 60 +/') -
$(printf "%(%s)T") % 86400 ))
0
.2 The $EPOCHSECONDS
and $EPOCHREALTIME
integer variables
From V5.0, bash's environment present two integer variables: $EPOCHSECONDS
which expands to the time in seconds since the Unix epoch and $EPOCHREALTIME
which expands to the time in seconds since the Unix epoch with microsecond granularity..
myvar1=$(LANG=C date -d 'now -1 day' +%c)
LANG=C printf -v myvar2 '%(%c)T' $(( EPOCHSECONDS - 86400 ))
[[ $myvar1 == "$myvar2" ]] || echo "Something's wrong: '$myvar1' != '$myvar2'!"
Except in a very small time laps, where time rounded to second increment by one second between setting $myvar1
and $myvar2
, this code won't produce any output as $myvar1
should contain exactly same string than $myvar2
.
declare -p myvar{1,2}
declare -- myvar1="Tue Aug 2 11:11:35 2022"
declare -- myvar2="Tue Aug 2 11:11:35 2022"
As printf
is a builtin, there is no fork for assigning string variable from UNIXTIME conversion.
The only difference would be resource footprint, then execution time.
Further informations and recommendations about $EPOCHREALTIME
, see How to print current time in microseconds using bash builtin
.3 About GNU date
option -f
for many entries
Using GNU date
, if you plan to format a big bunch of unixtimestamp, you could use date
command as a filter.
First you have to add a At
(@
) before each timestamp, then date -f
could process each input lines in one operation:
sed 's/^/@/' < inputfile |
date -f - +'%A %d %b %Y, %T %Z'
Sample:
seq 123456789 $(((EPOCHSECONDS-123456789)/4)) $EPOCHSECONDS |
sed 's/^/@/' |
LANG=C TZ=GMT date -f - +'%A %d %b %Y, %T %Z'
Should produce something like:
Thursday 29 Nov 1973, 21:33:09 GMT
Thursday 30 Jan 1986, 11:53:49 GMT
Thursday 02 Apr 1998, 02:14:29 GMT
Wednesday 02 Jun 2010, 16:35:09 GMT
Wednesday 03 Aug 2022, 06:55:49 GMT
.4 Converting streamed logfile
This could be titled
Convert streamed Unix timestamp to date strings in real time.
Sample using tail -f squid/access.log
, from a remote server.
squid
logs look like:
1659526597.212 240128 192.168.0.184 TCP_TUNNEL/200 3383 CONNECT safebrowsing.googleapis.com:443 - HIER_DIRECT/172.217.168.74 -
1659526614.078 753 192.168.0.91 TCP_TUNNEL/200 3800 CONNECT shavar.services.mozilla.com:443 - HIER_DIRECT/44.236.110.253 -
To be able to remotely follow some squid proxy I could use this:
exec {fd}<> <(:) # This will open unnamed fifo.
Then
ssh root@proxyserver tail -f /var/log/squid/access.log |
tee >(
exec sed -ue 's/^\([0-9]\+\)\..*/@\1/'|
stdbuf -i0 -o0 date -f - +%c >/dev/fd/$fd
) |
sed -ue 's/^[0-9]\+\././'|
paste -d '' /dev/fd/$fd -
This will output without buffering, something like this:
Wed Aug 3 13:36:37 2022.212 240128 192.168.0.184 TCP_TUNNEL/200 3383 CONNECT safebrowsing.googleapis.com:443 - HIER_DIRECT/172.217.168.74 -
Wed Aug 3 13:36:54 2022.078 753 192.168.0.91 TCP_TUNNEL/200 3800 CONNECT shavar.services.mozilla.com:443 - HIER_DIRECT/44.236.110.253 -
Could be stopped by Ctrl+C, then re-run many time, until you close $fd
unnamed fifo by:
exec {fd}<&-