Unix history your way

history raxon rex
Credit: flickr / Raxon Rex

The Unix history command is a critically important tool for reviewing what you and others did on the systems you manage – both for troubleshooting and to make managing systems easier (e.g., What was that command I used last week that worked so well?). In today's post, we'll look at some of the options available for capturing the date and time that commands were entered and configuring how that information is displayed.

Capturing the date and time

One option available with your history files is to include in them the date and time that commands were run. This can prove very useful when trying to correlate things that happen on your system with commands that were being run at the time they happened.

To include date and time in your history file (assuming you're using bash as your shell), make use of the HISTTIMEFORMAT setting and select the format that you want to see. In the commands below, the following substitutions are being made:

%F Equivalent to the data in the %Y-%m-%d (e.g., 2016-06-11) format
%T is replaced by the time in the %H:%M:%S (e.g., 16:45:57) format

Once we select our HISTTIMEFORMAT setting, our history command output includes the date/time in that format.
$ export HISTTIMEFORMAT='%F %T '
$ echo 'Hello, World!'
Hello, World!
$ date
Sat Jun 11 15:15:02 EDT 2016
$ history | tail -3
 1022  2016-06-11 15:14:50 echo 'Hello, World!'
 1023  2016-06-11 15:15:02 date
 1024  2016-06-11 15:15:12 history | tail -3

The %F and %T options will lead to your seeing the date/time in what is probably the most useful format (ISO 8601 standard date and a 24 hour time). This format is probably the most popular both because it's not ambiguous and the large-to-small arrangement makes it easier to sort the data should you ever need to merge data from different systems.

The less obvious thing is that, regardless of which options you select for your date/time display, the same information will be stored in your history file. If you dump your .bash_history file using a command like od (octal dump), you should spot the extra data in there, though not in a recognizable date string format.

0034300 154 144 134 041 047 012 043 061 064 066 065 066 067 062 064 071
          l   d   \   !   '  \n   #   1   4   6   5   6   7   2   4   9
0034320 060 012 145 143 150 157 040 047 110 145 154 154 157 054 040 127
          0  \n   e   c   h   o       '   H   e   l   l   o   ,       W
0034340 157 162 154 144 041 047 012 043 061 064 066 065 066 067 062 065
          o   r   l   d   !   '  \n   #   1   4   6   5   6   7   2   5

If you change your mind and want to use a different date/time format, previously saved date and time information is simply reformatted according to your new preferences. Notice how the same three commands look different depending on the date/time presentation selection.

$ export HISTTIMEFORMAT='%F %T '
$ history | egrep "996|997" | grep -v grep
  996  2016-06-11 15:14:50 echo 'Hello, World!'
  997  2016-06-11 15:15:02 date

$ export HISTTIMEFORMAT='%A %T '
$ history | egrep "996|997" | grep -v grep
  996  Saturday 15:14:50 echo 'Hello, World!'
  997  Saturday 15:15:02 date

$ export HISTTIMEFORMAT='%D %T '
$ history | egrep "996|997" | grep -v grep
  996  06/11/16 15:14:50 echo 'Hello, World!'
  997  06/11/16 15:15:02 date

$ export HISTTIMEFORMAT='%A %r '
$ history | egrep "996|997" | grep -v grep
  996  Saturday 03:14:50 PM echo 'Hello, World!'
  997  Saturday 03:15:02 PM date

So, regardless of how you set your HISTTIMEFORMAT options, the same data fields are stored in your history file and your settings determine how they are displayed.

Another possibly unexpected thing that you might notice is that commands that you entered before you began capturing date and time information appear as if they had all been entered at the same time. Since there is no time associated with these commands in your history file, a single date a time is associated with each of the commands in your display.

  808  2016-06-11 15:20:21 cd
  809  2016-06-11 15:20:21 vi flipme
  810  2016-06-11 15:20:21 echo Hello, World! | ./flipme
  811  2016-06-11 15:20:21 ls /usr/bin/env
  812  2016-06-11 15:20:21 vi trythis.pl
  813  2016-06-11 15:20:21 chmod 700 trythis
  814  2016-06-11 15:20:21 chmod 700 trythis*
  815  2016-06-11 15:20:21 ./trythis.pl

If you want to see a list of the options available for date and time formatting, you can look at the list below or check out the man page for strftime (format date and time).

Notice that this list isn't just detailing how you can format the calendar date and time, but includes such things as week number and numeric day of week. There are a lot more options here than most of us would ever be tempted to use.

$ history | tail -4
 1007  Monday June export HISTTIMEFORMAT="%A %B"
 1008  Monday June history | tail -4
 1009  Monday June export HISTTIMEFORMAT="%A %B "
 1010  Monday June history | tail -4
$ export HISTTIMEFORMAT="%W %w "
$ history | tail -4
 1009  24 1 export HISTTIMEFORMAT="%A %B "
 1010  24 1 history | tail -4
 1011  24 1 export HISTTIMEFORMAT="%W %w "
 1012  24 1 history | tail -4

strftime options

       %a     The abbreviated weekday name according to the current locale.
       %A     The full weekday name according to the current locale.
       %b     The abbreviated month name according to the current locale.
       %B     The full month name according to the current locale.
       %c     The  preferred date and time representation for the
              current locale.
       %C     The century number (year/100) as a 2-digit integer. (SU)
       %d     The day of the month as a decimal number (range 01 to 31).
       %D     Equivalent to %m/%d/%y. (Yecch—for Americans only.
              Americans should  note  that in other countries %d/%m/%y is
              rather common. This means that in international context this
              format is  ambiguous and should not be used.) (SU)
       %e     Like %d, the day of the month as a decimal number, but a
              leading zero is replaced by a space. (SU)
       %E     Modifier: use alternative format, see below. (SU)
       %F     Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)
       %G     The ISO 8601 week-based year (see NOTES) with century as a
              decimal number. The 4-digit year corresponding to the ISO
              week number (see %V). This has the same format and value as
              %Y, except that if the ISO week number belongs to the
              previous or next year, that year is used instead. (TZ)
       %g     Like %G, but without century,  that is, with a 2-digit
              year (00-99). (TZ)
       %h     Equivalent to %b.  (SU)
       %H     The  hour as a decimal number using a 24-hour clock (range
              00 to 23).
       %I     The hour as a decimal number using a 12-hour clock (range 01
              to 12).
       %j     The day of the year as a decimal number (range 001 to 366).
       %k     The hour (24-hour  clock) as a decimal number (range 0 to
              23); single digits are preceded by a blank.  (See also %H.)
              (TZ)
       %l     The hour (12-hour clock) as a decimal number (range 1 to 12);
              single digits are preceded by a blank.  (See also %I.)  (TZ)
       %m     The month as a decimal number (range 01 to 12).
       %M     The minute as a decimal number (range 00 to 59).
       %n     A newline character. (SU)
       %O     Modifier: use alternative format, see below. (SU)
       %p     Either  "AM"  or  "PM" according to the given time value, or
              the corresponding strings for the current locale. Noon is
              treated as "PM" and midnight as "AM".
       %P     Like %p but in lowercase: "am" or "pm" or a corresponding
              string for the current locale. (GNU)
       %r     The time in a.m. or p.m. notation.  In the POSIX locale this
              is equivalent to %I:%M:%S %p. (SU)
       %R     The  time in 24-hour notation (%H:%M). (SU) For a version
              including the seconds, see %T below.
       %s     The number of seconds since the Epoch, 1970-01-01 00:00:00
              +0000 (UTC). (TZ)
       %S     The  second as a decimal number (range 00 to 60). (The range
              is up to 60 to allow for occasional leap seconds.)
       %t     A tab character. (SU)
       %T     The time in 24-hour notation (%H:%M:%S). (SU)
       %u     The day of the week as a decimal, range 1 to 7, Monday being
              1. See also %w. (SU)
       %U     The  week  number of the current year as a decimal number,
              range 00 to 53, starting with the first Sunday as the first
              day of week 01. See also %V and %W.
       %V     The  ISO 8601 week number (see NOTES) of the current year as a
              decimal number, range 01 to 53, where week 1 is the  first
              week that has at least 4 days in the new year. See also %U and
              %W. (SU)
       %w     The day of the week as a decimal, range 0 to 6, Sunday being 0.
              See also %u.
       %W     The week number of the current year as a decimal number, range
              00 to 53, starting with the first Monday as the first day of
              week 01.
       %x     The preferred date representation for the current locale
              without the time.
       %X     The preferred time representation for the current locale
              without the date.
       %y     The year as a decimal number without a century (range 00 to
              99).
       %Y     The year as a decimal number including the century.
       %z     The +hhmm or -hhmm numeric timezone (that is, the hour and
              minute offset from UTC). (SU)
       %Z     The timezone name or abbreviation.
       %+     The date and time in date(1) format. (TZ) (Not supported in
              glibc2.)
       %%     A literal '%' character.

Your command history can be considerably more useful if it records the date and time that commands were issued. Your choice of which options to use, on the other hand, might just depend on your mood!

This article is published as part of the IDG Contributor Network. Want to Join?

To express your thoughts on Computerworld content, visit Computerworld's Facebook page, LinkedIn page and Twitter stream.
Related:
Windows 10 annoyances and solutions
Shop Tech Products at Amazon
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.