Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cache a variable used inside a Bash Completion Script for the current session

Inside my Bash Completion file, i'm looking up completion-strings by an external script, which takes some time (1-2 seconds). Since these strings mostly stay the same for the rest of the time the current shell runs, i want to cache them and when the Bash completion is triggered the next time, it should use the cached string instead of the expensive lookup, so that it completes immediately when its run the second time.

To get a feeling about by completion file, here is the important part of the completion file:

getdeployablefiles()
{
  # How can i cache the result of 'pbt getdeployablefiles'
  # for the time the current shell runs? 
  echo `pbt getdeployablefiles`
}

have pbt &&
_pbt_complete()
{
  local cur goals

  COMPREPLY=()
  cur=${COMP_WORDS[COMP_CWORD]}
  goals=$(getdeployablefiles)
  COMPREPLY=( $(compgen -W "${goals}" -- $cur) )
  return 0
} &&
complete -F _pbt_complete pbt

How can i cache the output of getdeployablefiles for the rest of the shell session? I need some kind of global variable here, or some other trick.

Solution:

Just had to make goals non-local and ask if it's set. The final script:

getdeployablefiles()
{
  echo `pbt getdeployablefiles`
}

have pbt &&
_pbt_complete()
{
  local cur 
  if [ -z "$_pbt_complete_goals" ]; then
    _pbt_complete_goals=$(getdeployablefiles)
  fi

  _pbt_complete_goals=$(getdeployablefiles)

  COMPREPLY=()
  cur=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -W "${_pbt_complete_goals}" -- $cur) )
  return 0
} &&
complete -F _pbt_complete pbt
like image 345
Wolkenarchitekt Avatar asked Mar 16 '11 15:03

Wolkenarchitekt


3 Answers

Why not leave goals out of the local statement and rename it to something with a low likelihood of name collision, _pbt_complete_goals perhaps? Then you could check to see if it's null or unset and set it if necessary.

like image 172
Dennis Williamson Avatar answered Sep 18 '22 14:09

Dennis Williamson


One approach you could consider is using bkt to cache the data for you. Something like:

_pbt_complete() {
  local cur=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -W "$(bkt --ttl=10m -- pbt getdeployablefiles)" -- "$cur") )
}

Should work. This offloads all the caching logic to bkt which invokes pbt whenever there's a cache miss. It also works across shell sessions, so you don't need to wrestle with variable scoping or the like.

If you want to limit the cache to a given shell session you can pass --scope="_pbt_complete_$$" ($$ expands to the current PID).

And if you want to refresh the cache in the background you can pass --stale=1m to invoke pbt asynchronously when the cache is warm but old. Obviously you can tune the --ttl and --stale durations as you see fit.

Disclaimer: I am the author of bkt

like image 23
dimo414 Avatar answered Sep 19 '22 14:09

dimo414


You could write the cached values to a file with the PID of the current shell, then source it and check that the PID matches. If it does, use the cached value, otherwise recalculate.

like image 27
Daenyth Avatar answered Sep 19 '22 14:09

Daenyth