Last command and execution time
NOTE: I'm assuming bash
as the shell.
Adapting to other shells shouldn't be difficult.
Getting the last command used is trivial: it's stored in the shell event designator !!
, and can also be obtained using the shell builtins fc
(fc -s
) or history
(with some string manuipluation: history 1 | awk '{$1=""}1'
).
Getting the time of execution, or the running time, however, is not, unless some action is taken before the command has executed. Once the command is run, nothing can be done - the horses have bolted.
For getting the time of execution, either:
- Set the
HISTTIMEFORMAT
variable, which would makebash
save the time of execution in the history, then use text processing to extract the time from the output ofhistory
. - Use a wrapper to save the execution time manually.
For getting the running time, again, either:
- If you had set
HISTTIMEFORMAT
before running the command, you could parse the output ofhistory
to get the execution time and then calculate the run time. - Use a wrapper to run the command with
time
:time some-command
. Processing the output oftime
is a bit messy if you want to leave the output of the command untouched. - Use a wrapper to calculate runtime based on manually saved execution time.
With HISTTIMEFORMAT
set
If you set the HISTTIMEFORMAT
variable, then you need not use a wrapper.
First, in your .bashrc
, set HISTTIMEFORMAT
. You can set it to anything, as long as it's not empty. If you don't want your history
command to show the time, you could set it to a space (HISTTIMEFORMAT=" "
).
Now, there's an alias present in the default .bashrc
of Ubuntu:
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
We can adapt it for our purposes:
alert_post ()
{
RET=$?;
END=$(date '+%s');
LAST_COMM="$(HISTTIMEFORMAT='%s '; history 1)";
START=$(awk '{print $2}' <<<"$LAST_COMM");
START_TIME=$(date -d"@$START" '+%T %D');
COMM=$(awk '{print $3}' <<<"$LAST_COMM");
notify-send --urgency=low -i "$([ $RET = 0 ] && echo terminal || echo error)" "$COMM started at $START_TIME finished in $((END - START)) seconds.";
return $RET
}
alias a=alert_post
You can use it thus:
$ sleep 10; a
Wrapper function
Using a function or a script to wrap around the command:
alert_wrapper ()
{
START=$SECONDS;
START_TIME=$(date '+%T %D');
COMM="$1";
"$@";
RET=$?;
END=$SECONDS;
notify-send --urgency=low -i "$([ $RET = 0 ] && echo terminal || echo error)" "$COMM started at $START_TIME finished in $((END - START)) seconds."
return $RET
}
alias a=alertwrapper
Then run your command prefixed with a
:
$ a sleep 10
Notes:
- There are many ways of getting the time, both execution and runtime. I used both the
$SECONDS
special variable and thedate
command. You could get by with only thedate
command. - I have used
notify-usd
, which should be available on standard Ubuntu. You could look at other ways of producing notifications. - I have saved the exit status of the command in
$RET
and returned it, so you should be able to rely on exit codes:do-something; a || echo "Couldn't do something."
ora do-something || echo "Couldn't do something."
willecho
ifdo-something
had a non-zero exit status.
atlaspaine
Updated on September 18, 2022Comments
-
atlaspaine over 1 year
I'd like to get the last command used and its execution time. This will be used as part of an alias for notification.
-
muru over 9 yearsBy execution time, do you mean time of execution or running time?
-
atlaspaine over 9 yearsGood point. Both.
-
-
hunteke about 6 yearsThis is a fantastic answer, and I'm sorry it wasn't accepted when you first wrote it.