12

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.)

4 Answers 4

2

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).

1

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.

3
  • Good advices. Unfortunately, in my specific case, this won't help on Mac OSX, since in there the shells are always loaded as login-shell leading to always source the profile, every time a new terminal is created. Thank you Apple. Jul 10, 2019 at 16:44
  • Hmmm; that's something I find useful — I open a new terminal on my Macs and it runs my profile for me. That's what I want. When I run a shell within that window, the minimal .bashrc keeps that startup fast. It annoys me endlessly when a terminal is popped up with a shell and it doesn't run my profile. Each to their own, and YMMV, as they say. Jul 10, 2019 at 16:49
  • Lucky you :) – From what I read around, Apple's is a buggy implementation of the bash model. The profile files are supposed to be run just once (on OSX should be at user login, I suppose), while each new terminal should run .bashrc. But since Apple switched to bash they aren't doing any of them; always running a login-shell` for each new terminal, and never running the .bashrc. Might be suitable for use cases when there's no intensive configuration via shell scripts, but it is basically broken; breaks the expectations created in the docs, at the *INVOCATION section of man bash. Jul 11, 2019 at 10:45
1

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>&-
1
  • 1
    ewindisch, could you add some comments to the right of the exec statements? I can never seem to remember how to properly (and safely!) use the <& and >& forms of redirection.
    – Zearin
    Jan 20, 2014 at 16:13
0

You can use an ampersand to run a process in the background.

some_program &

However, the program won't be able to directly affect the environment of the shell that started it.

You should not have any long-running processes in startup files.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .