Run parts of .bashrc asynchronously
I have some exports and other things that require another program to run (to get paths or whatever) and they take a non-trivial amount of time to run, meaning my bash startup time is on the order of 5 seconds.
Before I go off and add some basic caching in my .bashrc
, is there a way I can run something asynchronously that will allow me to export variables in my running shell?
(So, this really isn't limited to .bashrc
, but bash in general.)
A lot depends on when those programs have to run and when you need their results. If it doesn't matter when they run (that is, their results don't vary with time), then it might be better to have them run from your ~/.profile
or ~/.bash_profile
(i.e., when you log in) rather than from your ~/.bashrc
.
If you need their results, but can't wait the 5 seconds it takes for them to run, what are you going to do for the first 5 seconds that your shell is up? You can't run any commands that depend on the outputs of those programs, because the results won't be available yet.
I think if you describe in more detail exactly what the requirements are, we might be able to give you better answers.
All that said, you could launch your programs in the background as Dennis Williamson suggested, and have them write their results to some files in your home directory. Then you could set the bash variable PROMPT_COMMAND
to source those files, which bash would then do before every display of PS1
.
For example, say your background program writes export ans=42
to the file ~/answer
when it's done. In your ~/.bashrc
, put
PROMPT_COMMAND=". ~/answer"
Then every time the shell displays PS1
, it will first source ~/answer
and your environment will eventually (e.g., 5 seconds after starting) contain the variable ans
with the value 42
.
Of course, the first 5 seconds after you start the shell, ~/answer
will contain the values from the last time you started a shell, so you'd have to decide whether that's important (and how to reset that file if necessary).
You might want to think about balancing the workload between your profile, which is executed once, and your bashrc file, which is executed whenever you start (an interactive) bash. I keep my bashrc minimal - so I get fast start up. My profile isn't too bad - it is complex, but it certainly doesn't take 5 seconds.
I'm not aware of any way that can set the variables in the background. However, you can run scripts in background such that they run in parallel, rather than sequentially, while catching their output. This can speed up execution. You can use file descriptors 3-9 with this method for a total of 7 parallel processes.
To be clear, all of the commands executed must finish before spawning the interactive shell in order to use their output in setting variables.
This solution simply allows parts of the script to run in parallel to the rest of the script (in this case, the .bashrc
)
function copget { read -u $1; echo "$REPLY"; }
coproc DATE { date; }
exec 3<&${DATE[0]}
coproc UNAME { uname; }
exec 4<&${UNAME[0]}
var1=$(copget 3)
exec 3>&-
var2=$(copget 4)
exec 4>&-