
When did I run that command? Update your Bash prompt with the command start time - countermeasure
https://redandblack.io/blog/2020/bash-prompt-with-updating-time/
======
naggie
I do something similar -- I show the duration of the command in a human
readable format, but only if the command too more than 60 seconds; useful to
get an idea of how long compilations (etc) take

See
[https://github.com/naggie/dotfiles/blob/master/home/.functio...](https://github.com/naggie/dotfiles/blob/master/home/.functions.sh#L148)

One of my most useful changes is a script that garbage-collects my history
file: deduplication, removal of sensitive + trivial commands. In combination
with a FZF based history search that's shared between all shells, I
effectively have a super-quick database of every command without any noise.
See
[https://github.com/naggie/dotfiles/blob/master/scripts/clean...](https://github.com/naggie/dotfiles/blob/master/scripts/cleanup-
history) \-- added via bash/zsh hooks.

~~~
nikeee
> I show the duration of the command in a human readable format, but only if
> the command too more than 60 seconds

There is also a similar builtin feature [1] of ZSH. For example, you can put
this in your .zshrc:

    
    
        REPORTTIME=10
    

It instructs ZSH to report the time elapsed since the command was invoked (if
it is above this threshold, 10 seconds in this case). However, it just takes
the CPU time into account. When using something like `sleep`, it won't
trigger. There is a plugin [2] that covers this use case aswell.

[1]: [https://nuclearsquid.com/writings/reporttime-in-
zsh/](https://nuclearsquid.com/writings/reporttime-in-zsh/) [2]:
[https://github.com/popstas/zsh-command-time](https://github.com/popstas/zsh-
command-time)

~~~
naggie
Hm, I didn't know about that. Thanks. Though, I use bash mostly.

------
countermeasure
For years I wanted a Bash prompt which would show when a command actually ran.

I don't mean that it would show the time when the prompt was written to the
terminal. That's easy.

I mean that it would show the time when the command entered at it was
executed. Those two times can be very different.

This little hack updates your Bash prompt with the current time when you
execute a command.

As someone who spends many hours every day in the terminal, it's improved my
life. Maybe it can help you too.

~~~
nicwolff
This is handy, but if you just want the ability to see when you ran a previous
command you can add

    
    
        export HISTTIMEFORMAT="%d/%m/%y %T "
    

to your .bashrc and then

    
    
        history
    

will show the date and time before each command that was run.

~~~
kyuudou
I'm sure most know this but if anyone thinks this is a way of doing forensics,
keep in mind it can be easily skipped over by doing a non-standard logout,
like "kill -9 $$" or if a remote ssh connection gets cut for whatever reason.
The command history for a session won't get written until logout by default. A
workaround such as forcing each entry to be written to a log file will have to
be done to have better assurance of true history.

~~~
kubanczyk
> forcing each entry to be written to a log file

When I last needed it ~2011, there was a small and simple tool called
libsnoopy for that.

Emphasis on "log file" though, the "history file" is a different use case,
fundamentally unfit for forensics.

------
albertzeyer
In our research group (with shared NFS), we log the history per directory
(i.e. the histfile is $PWD/.history.$USER), and we also log the date/time.
This has been extremely helpful. Not only checking your own history, but also
being able to see others history. E.g. imagine going through some directories
of some former colleague who is gone now. Otherwise it would often be
impossible to really understand how sth was created, or ended up that way,
etc. I mean, properly documenting everything is of course nice, but even if
that is done consistently, it will still miss some details. And in practice,
it never is done consistently.

I wonder why this is not more standard. Most shells write a single global
histfile to $HOME.

~~~
sdoering
how do you configure this? I would love to use this.

~~~
albertzeyer
It's a very custom solution.

For Bash, in ~/.bashrc:

    
    
        export PROMPT_COMMAND="myLocalHistory"
    
        # we don't need everything within the history 
        alias useHistory='grep -E -v "^ls$|^ll$|^l$|^dir$|^cd |^bg$|^fg$|^qstat |^note |^mutt|^std|^clear$|^qinfo$|^gh|^qw$"  | wc -l'
    
        function myLocalHistory()
        {
          HISTORYLINE=`history | tail -1 | sed 's:^ *[0-9]* *::g'`
          if [ `echo $HISTORYLINE | useHistory` == 1 ] ; then
            ((date +%F.%H-%M-%S | tr -d '\n' ; echo " $HISTORYLINE") >>.history.$USER) 2>/dev/null
          fi
        }
    

For ZSH, in ~/.zshrc:

    
    
        preexec () {
            ~/dotfiles/system-tools/helpers/local-history-add.py $1 >/dev/null
        }
    

For Fish, in ~/.config/fish/config.fish:

    
    
        function fish_preexec --on-event fish_preexec
            ~/dotfiles/system-tools/helpers/local-history-add.py $argv &
        end
    
    

The script local-history-add.py is here:
[https://github.com/albertz/helpers/blob/master/local-
history...](https://github.com/albertz/helpers/blob/master/local-history-
add.py)

The Bash solution probably could also be simplified by using this script,
which takes care of filtering logic and adding it to the history file, in your
preferred format.

------
vietjtnguyen
I just write all my commands to a log. It's saved me a number of times.

[https://spin.atomicobject.com/2016/05/28/log-bash-
history/](https://spin.atomicobject.com/2016/05/28/log-bash-history/)

~~~
varenc
You can do this easily with zsh’s standard features. I love having years of my
command history! It's all combined across sessions and instantly searchable
with the standard ^R.

These are most of the settings in ZSH I use to enable all that.

    
    
      HISTSIZE=10000000
      SAVEHIST=10000000
     
      setopt EXTENDED_HISTORY # logs the start and elapsed time
      setopt INC_APPEND_HISTORY   
      setopt SHARE_HISTORY
      setopt HIST_IGNORE_DUPS     
      setopt HIST_IGNORE_ALL_DUPS
      setopt HIST_FIND_NO_DUPS
    

Apple now even recommends zsh shell over bash! =)
[https://support.apple.com/en-us/HT208050](https://support.apple.com/en-
us/HT208050) (it's the 10.15 default)

~~~
TwoNineFive
> Apple now even recommends zsh shell over bash!

Worth reading why they did that: [https://thenextweb.com/dd/2019/06/04/why-
does-macos-catalina...](https://thenextweb.com/dd/2019/06/04/why-does-macos-
catalina-use-zsh-instead-of-bash-licensing/)

------
pronoiac
In iTerm2 on Macs, command-E shows timestamps of lines in an overlay, with
dates and down to the second.

~~~
yen223
It's cmd-shift-E on my version of iTerm2. Not sure if they changed it at some
point.

~~~
cs02rm0
(I assume) cmd-E _is_ cmd-shift-e.

As in, the shift key's required.

~~~
pronoiac
You're correct! I was trying to be concise, but instead I caused confusion.

------
akavel
I have a much shorter snippet in .profile for bash:

    
    
        if $INTERACTIVE; then
          # http://superuser.com/a/175802
          # show date when command was executed
          preexec() {
              [ -n "$COMP_LINE" ] && return  # do nothing if completing
              [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
    
              echo -ne "\033[$(( COLUMNS-15 ))C$(date +'%m%d-%H:%M:%S')\r"
          }
          trap 'preexec' DEBUG
        fi
    

The `echo -ne ...` is what prints the date (month+day+time, year is assumed
obvious) close to the right margin (COLUMNS-15), then prints `\r` to get back
to left margin. This has pros (less space taken) and cons (shows up in
copy&paste), you can surely edit the format to your liking if you prefer.

I'll have to check how the OP's PS0 compares with that however, maybe it can
make my snippet even simpler? _edit:_ Ah, IIUC, PS0 seems bash 4.4+, for
better or worse: [https://github.com/rcaloras/bash-
preexec/issues/28](https://github.com/rcaloras/bash-preexec/issues/28)

------
mbreese
And I like storing the time the prompt was printed so that I can keep track of
how long a command took. When I care to keep track of when a command started,
I just hit enter once or twice to get a “fresh” timestamp, then I have both an
accurate start time and an accurate stop time. This is very handy if you run
long jobs in a tmux session, for example.

If I rewrote the prompt each time I ran a command, I’d lose that record. (I
suppose I could do the same trick in reverse and if I care to know how long a
command will take, I could run it and hit enter a few times to queue up an
empty command to create the same timestamp effect after the fact).

~~~
countermeasure
I'm not sure how it would suit your workflow, but you could try out
PROMPT_COMMAND.

[https://www.gnu.org/savannah-
checkouts/gnu/bash/manual/bash....](https://www.gnu.org/savannah-
checkouts/gnu/bash/manual/bash.html#index-PROMPT_005fCOMMAND)

It's executed just before the PS1 prompt is printed.

A nice idea I've seen is to use PROMPT_COMMAND to print the time a command
finished (and maybe an indication of its exit status) in low-contrast text at
the far right of the terminal. Then that info is there if you want to look for
it, but it's not distracting.

Then you could have the best of both worlds, and it would all happen without
the need to remember to create fresh prompts.

------
graton
Sort of related, I like to put this snippet in my PROMPT_COMMAND variable:

PROMPT_COMMAND='echo "$(date "+%Y-%m-%d.%H:%M:%S") $(pwd) $(HISTTIMEFORMAT=
history 1)" >> ~/.logs/bash/bash-history-$(date "+%Y-%m-%d").log'

I forget where I learned this. What it does is write the bash history to a log
file, with the date/time, directory of the command, and the command.
Occasionally it has helped me find where a file is that I was working on :)

------
awinder
I switched over to zsh a few months back and picked up something like this
method:
[https://gist.github.com/zulhfreelancer/9c410cad5efa9c5f7c74c...](https://gist.github.com/zulhfreelancer/9c410cad5efa9c5f7c74cd0849765865).
This is nice to see for bash and I definitely agree on the usefulness notes,
it’s been a nice improvement / helped me not get confused a few times

~~~
mikelward
Isn't that printing the time the prompt was printed (the time the previous
command finished)?

This is printing the time you pressed Enter (the time the command started),
which is harder and less common, since that's not when the prompt is printed.

~~~
mikelward
This is one way you could do something similar in zsh:
[https://stackoverflow.com/a/17915260/102182](https://stackoverflow.com/a/17915260/102182)

~~~
countermeasure
It looks like zsh can handle updating the time in the prompt quite simply and
elegantly.

~~~
mikelward
Yes, I find that solution much simpler.

~~~
Symbiote
It keeps the clock up-to-date, but I use Konsole's "monitor for activity"
feature, which changes the colour of inactive tabs if there is output.

Instead, this seems to work:

    
    
      TRAPDEBUG() {
        case "$WIDGET" in
          zle-line-finish)
            zle reset-prompt
            ;;
          *)
            ;;
        esac
      }
    

(I don't know if further cases will be required.)

This updates the prompt after "enter" is pressed, but before the command is
executed.

------
sdegutis
If you're using zsh and have a date like %D{...} in your prompt, set TMOUT=1
and define TRAPALRM to run `zle reset-prompt` and your date will auto-update.
Full prompt at
[https://github.com/sdegutis/dotfiles/blob/master/.zshrc#L3-L...](https://github.com/sdegutis/dotfiles/blob/master/.zshrc#L3-L19)
fwiw.

------
b0rsuk
I think it would be more useful to know _where_ did I run the command. That
bit of context is often lost unless you use absolute paths a lot.

~~~
stragies
add this to you "~/.inputrc" :

"\C-xj": "\C-e\C-u # `pwd`\e\C-e\C-a\C-y\C-j"

Whenever you want a command saved with the launch directory, instead of Enter,
press "CTRL-x j"

~~~
b0rsuk
Why not make it default?

------
lotia
Thanks for sharing this guide. For those (like me) who are lazy and want to
delegate the hard work and maintenance to folks smarter than me, starship is a
cross-shell prompt that will print duration of commands.
[https://starship.rs/](https://starship.rs/)

------
aembleton
Bob the fish theme gives me this and places it on the right hand side of the
prompt: [https://github.com/oh-my-fish/theme-
bobthefish](https://github.com/oh-my-fish/theme-bobthefish)

------
hunter2_
All these neat tricks being discussed, and meanwhile I just `date; my_cmd;
date` for jobs I want start/end times of. The fact that I can do it with no
configuration on all the umpteen boxes I log into is the reason I stick with
it.

~~~
fizixer
or, if you're only interested in the time it took for the command to run:

    
    
        time my_cmd

~~~
alpaca128
All of those are only useful if you thought of it beforehand. Which is rare in
my experience, often I want to know the time exactly when something unexpected
happened.

------
Normal_gaussian
If you also write the starttime to a file you can read it and produce the
elapsed time. Then one step further is to have a program read all your ongoing
times alongside parsing the active processes, and give you running progress of
your current shells.

Mine works but is hacky, it would be nice to have a more neatly packaged
solution.

~~~
countermeasure
I think that hacks are the name of the game when it comes to this sort of
thing with Bash, so don't feel bad about that. My solution is very much a hack
too.

------
ddevault
I do something similar, but I print uptime instead of wall-clock time.

[https://git.sr.ht/~sircmpwn/dotfiles/tree/master/bin/prompt....](https://git.sr.ht/~sircmpwn/dotfiles/tree/master/bin/prompt.go)

------
ChrisMarshallNY
It's pretty cool. I probably won't use it, because it's rather "heavy," and I
don't really need it, but I like.

I suspect that we'll be seeing a lot more of these kinds of things, coming out
of this "house arrest" situation.

------
Bnshsysjab
I wrap every interactive shell in ‘script’ effectively recording it.

I’ve been tempted to add time logging by something similar to
PS1=“$(date)\r$PS1” Because I don’t really care about the execution time of
current commands but might care historically.

~~~
countermeasure
If I'm understanding it correctly, what this sort of approach will give you is
a timestamp in the prompt which is generated when the prompt is printed to the
terminal and then doesn't change.

The thing is that the prompt might sit there for minutes or hours before you
use it to run a command, so that timestamp doesn't reliably serve as an
accurate record of when a command was run.

That's the problem which my approach addresses by updating the timestamp when
a command is run.

~~~
Bnshsysjab
Sure, forensics accuracy isn’t something I hugely care about, i do have some
shell sessions that span days so having an indication can be handy.

If I did, It’s also possible to get amount of time a command required to
complete. Based on that execution time in conjunction with the timestamp of
the next print of PS1 it would be easy to deduce the time when a line was
actually executed, rather than when typing of the line began, but at that
point I’d probably just record my screen to track any harder to determine
behaviours.

------
acqq
And I discovered that I like to always see in the prompt the return value of
the last command executed, if it is not 0. nd that I don't need the name of
the machine and the user name in the prompt on my main computer.

------
x3n0ph3n3
I found the requirement for shopt -s histverify unbearable. I use !!
extensively and don't want to hit enter twice.

------
question11
AS400 had this..! all commands logged to a sql style database and a way to
revert them (a revertible rm -rf *). Very cool

------
envolt
I do this on iTerm CMD + Shift + E

Is it the same or something different?

------
ducktective
[https://starship.rs/config/#command-
duration](https://starship.rs/config/#command-duration)

------
dummytummy
Hmm

