Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is it possible to forcibly add a timing alias (for lack of a better way to phrase it) to every command in bash?

For example, I would like to have a specific user who whenever a command is run, it is always wrapped either with date before and after, or time.

Is this possible, and, if so, how?

share|improve this question
    
I looked before, and couldn't find a way to do exactly this. As Caleb says, you can use preexec, but you don't want to run it inside the preexec (e.g. preexec() { time $1; }), because the shell still runs it after preexec returns. So the best we can do is something similar. –  Mikel Apr 26 '11 at 23:35
    
@Mikel I think you could use the preexec() function to actually wrapper whatever was executing by fetching the command, running it yourself from inside the function, then returning some sort of error so that the shell doesn't go on to execute the command itself. –  Caleb Sep 11 '12 at 22:02

4 Answers 4

up vote 6 down vote accepted

You can record the time a command line is started and the time a prompt is displayed. Bash already keeps track of the starting date of each command line in its history, and you can note the time when you display the next prompt.

print_command_wall_clock_time () {
  echo Wall clock time: \
    $(($(date +%s) - $(HISTTIMEFORMAT="%s ";
                       set -o noglob;
                       set $(history 1); echo $2)))
}
PROMPT_COMMAND=print_command_wall_clock_time$'\n'"$PROMPT_COMMAND"

This only gives you second resolution, and only the wall clock time. If you want better resolution, you need to use an external date command that supports the %N format for nanoseconds, and the DEBUG trap to call date before running the command to time.

call_date_before_command () {
  date_before=$(date +%s.%N)
}
print_wall_clock_time () {
  echo Wall clock time: \
    $((date +"$date_before - %s.%N" | bc))
}
trap call_date_before_command DEBUG
PROMPT_COMMAND=print_command_wall_clock_time

Even with the DEBUG trap, I don't think there's a way of automatically displaying processor times for each command, or being more discriminating than prompt to prompt.


If you're willing to use a different shell, here's how to get a time report for every command in zsh (this doesn't generalize to other tasks):

REPORTTIME=0

You can set REPORTTIME to any integer value, the timing information will only be displayed for commands that used more than this many seconds of processor time.

Zsh took this feature from csh where the variable is called time.

share|improve this answer

Your options here are going to depend on your shell. In zsh there a conveneient hook function called preexec() that is run right before any interactive shell commands. By creating creating a function with this name, you can cause things to be executed. You can also follow up follow up with a function called precmd() which will run just before the next prompt is drawn, which will be right after your command finishes.

By creating this pair of functions, you can have whatever arbitrary comands you want run before and after whatever commands are issued at the prompt. You could use this to log shell usage, create locks, test the environment, or as in your example calculate time or resources spent while a command runs.

In this example, we will create ourselves a benchmark timestamp before running a command using preexec() then calculate the time spent executing the command using precmd() and output it before the prompt or log it away. Example:

preexec() {
   CMDSTART=$(date +%s%N)
}
precmd() {
   CMDRUNTIME=$(($(date +%s%N)-$CMDSTART))
   echo "Last command ran for $CMDRUNTIME nanoseconds."
}

Note: For this particular example, there is an even easier builtin function. All you have to do is turn on runtime reporting in ZSH and it will do this automatically.

$ export REPORTTIME=0
$ ls -d
./
ls -BF --color=auto -d  0.00s user 0.00s system 0% cpu 0.002 total

In a more practical implementation of preexec(), I use it see if the shell is running inside tmux or screen and, if so, to send information about the currently running command upstream to be displayed in the tab name.

Unfortunately in bash this little mechanism doesn't exist. Here is one man's attempt to replicate it. Also see Gilles's answer for similar nifty little hack.

share|improve this answer
1  
And here's a simplified version of the precmd-through-DEBUG trick. –  Gilles Apr 26 '11 at 22:59
    
See also unix.stackexchange.com/questions/8607/… –  Mikel Apr 26 '11 at 23:30
    
wish this was available in bash! –  warren Apr 27 '11 at 19:46
    
See Gilles's and others links, it is implementable in bash with a little extra fiddling. The again, why don't you just run zsh? It's a rocking shell with more good reasons to switch than just this! –  Caleb Apr 27 '11 at 19:48
2  
If you're using zsh there is an even better way to do it. The REPORTTIME environment variable when set will output the execution time info (as if you had run the command with 'time' in front of it) for any command taking longer than $REPORTTIME seconds. Just set it to 0 and it should tell you the time for every command, with the user/sys breakdown to boot. –  Joseph Garvin Apr 27 '11 at 23:54

The easiest way would probably to set PROMPT_COMMAND. See Bash Variables:

PROMPT_COMMAND
If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).

For example, to avoid overwriting any existing prompt command, you could do:

PROMPT_COMMAND="date ; ${PROMPT_COMMAND}"
share|improve this answer
    
did not know about that one - looks like a good start, @cjm –  warren Apr 26 '11 at 18:12
1  
It's a start, but doesn't address the problem of knowing when a command was run. The prompt itself might be drawn minutes or hours or days before a command was typed and run. –  Caleb Apr 26 '11 at 23:17

csh/tcsh has the best support for this feature (and has always had it).

  The `time` shell variable can be set to execute the time builtin  command
  after the completion of any process that takes more than a given number
  of CPU seconds.

In other words, set time=1 will print out the time consumed (system, user, elapsed) by any command that took more than 1 second of cpu time. Plain set time will enable printing out the time for all commands.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.