Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

shell - Use PS0 and PS1 to display execution time of each bash command

It seems that by executing code in PS0 and PS1 variables (which are eval'ed before and after a prompt command is run, as I understand) it should be possible to record time of each running command and display it in the prompt. Something like that:

user@machine ~/tmp
$ sleep 1

user@machine ~/tmp 1.01s
$

However, I quickly got stuck with recording time in PS0, since something like this doesn't work:

PS0='$(START=$(date +%s.%N))'

As I understand, START assignment happens in a sub-shell, so it is not visible in the outer shell. How would you approach this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I was looking for a solution to a different problem and came upon this question, and decided that sounds like a cool feature to have. Using @Scheff's excellent answer as a base in addition to the solutions I developed for my other problem, I came up with a more elegant and full featured solution.

First, I created a few functions that read/write the time to/from memory. Writing to the shared memory folder prevents disk access and does not persist on reboot if the files are not cleaned for some reason

function roundseconds (){
  # rounds a number to 3 decimal places
  echo m=$1";h=0.5;scale=4;t=1000;if(m<0) h=-0.5;a=m*t+h;scale=3;a/t;" | bc
}

function bash_getstarttime (){
  # places the epoch time in ns into shared memory
  date +%s.%N >"/dev/shm/${USER}.bashtime.${1}"
}

function bash_getstoptime (){
  # reads stored epoch time and subtracts from current
  local endtime=$(date +%s.%N)
  local starttime=$(cat /dev/shm/${USER}.bashtime.${1})
  roundseconds $(echo $(eval echo "$endtime - $starttime") | bc)
}

The input to the bash_ functions is the bash PID

Those functions and the following are added to the ~/.bashrc file

ROOTPID=$BASHPID
bash_getstarttime $ROOTPID

These create the initial time value and store the bash PID as a different variable that can be passed to a function. Then you add the functions to PS0 and PS1

PS0='$(bash_getstarttime $ROOTPID) etc..'
PS1='[33[36m] Execution time $(bash_getstoptime $ROOTPID)s
'
PS1="$PS1"'and your normal PS1 here'

Now it will generate the time in PS0 prior to processing terminal input, and generate the time again in PS1 after processing terminal input, then calculate the difference and add to PS1. And finally, this code cleans up the stored time when the terminal exits:

function runonexit (){
  rm /dev/shm/${USER}.bashtime.${ROOTPID}
}

trap runonexit EXIT

Putting it all together, plus some additional code being tested, and it looks like this:

Terminal Output

The important parts are the execution time in ms, and the user.bashtime files for all active terminal PIDs stored in shared memory. The PID is also shown right after the terminal input, as I added display of it to PS0, and you can see the bashtime files added and removed.

PS0='$(bash_getstarttime $ROOTPID) $ROOTPID experiments [33[00m]
'

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...