awk '/^#[0-9]*$/ {split($0, arr, "#"); print "#", strftime("%c", arr[2]); getline; print }' < /path/to/.bash_history
When HISTTIMEFORMAT
is set, the command history of a Bash shell will be written to $HISTFILE
, with comment lines of the timestamp of the command in epoch format, for example:
#1583857757
history
#1583857774
grep HIST /etc/bashrc
#1583857783
grep HIST /etc/skel/.bash_profile /etc/skel/.bashrc
#1583857945
tail .bash_history
The one-liner converts the epoch dates in this format into human readable dates to look like this:
# Tue 10 Mar 2020 04:29:17 PM UTC
history
# Tue 10 Mar 2020 04:29:34 PM UTC
grep HIST /etc/bashrc
# Tue 10 Mar 2020 04:29:43 PM UTC
grep HIST /etc/skel/.bash_profile /etc/skel/.bashrc
# Tue 10 Mar 2020 04:32:25 PM UTC
tail .bash_history
With awk '...' < /path/to/file
we execute Awk commands in ...
, using the content of /path/to/file
as the input, with the <
input redirection operator.
The first part of the Awk command /.../
is a filter: it matches lines in the input with the regular expression in ...
. The regular expression ^#[0-9]*$
matches lines that start with a "#", followed by zero or more digits until the end of the line.
For the matched pattern, Awk executes all the commands within the following { ... }
block.
split($0, arr, "#")
splits the line ($0
) by #
, storing the result in the array variable arr
print "#", strftime("%c", arr[2])
prints a line, starting with #
, followed by a space, followed by the value of arr[2]
formatted as s human readable time. arr[2]
contains the timestamp in epoch format, notice that arrays in Awk use 1 as the starting index. If we take for example the input #123
, then arr[1]
is the empty string, and arr[2]
is 123.strftime("%c", ...)
formats a value as a human readable date. See man strftime
for other possible formats.getline
reads the next line of input and stores in the variable $0
print
simply prints the content of the variable $0