Cannot successfully source .bashrc from a shell script
Normally we can source ~/.bashrc
file using this command
source ~/.bashrc
but if I write this in a shell script and execute it, nothing happens. Why?
Is there any way to do this?
My script:
#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc
Also tried .
(dot) instead of source
. Same result.
Solution 1:
A shell script is run in its own shell instance. All the variable settings, function definitions and such only affect this instance (and maybe its children) but not the calling shell so they are gone after the script finished.
By contrast the source
command doesn't start a new shell instance but uses the current shell so the changes remain.
If you want a shortcut to read your .bashrc use a shell function or an alias instead of a shell script, like
alias brc='source ~/.bashrc'
Solution 2:
I want to complement ravi's answer:
This behavior is specific to Ubuntu (and probably most derived distros), since your default ~/.bashrc
file starts with a short-circuit, Ubuntu 18.04, for example:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That will stop the evaluation of the file if it is running in a non-interactive shell, which is the case of your script since all scripts are run in a non-interactive shell, and subsequently every file you source
will inherit this property.
eval
hack
I found out an ugly hack to workaround Ubuntu specifically, using eval
instead of source
:
eval "$(cat ~/.bashrc | tail -n +10)"
It simply skips the few first lines and evaluates the rest of the ~/.bashrc
so the rest is evaluated and modifies the current execution.
Be aware it is a magic number and might not work across Ubuntu versions; but may be a good solution if your are crafting scripts for more-or-less known systems.
A fancier solution might involve using regex to target the specific bits that stop the evaluation.
Shebang alternative
Another alternative that might work better in some scenarios is forcing the script to run in an interactive shell by adding a flag in the shebang:
#!/bin/bash -i
Be aware of a few things:
- It is a better practice to use the
#!/usr/bin/env bash
form but this way you cannot start the shell with arguments. - Using the
-i
has it's own set of consequences, among them, programs will prompt for user interaction and this is usually not intended for scripts, for example, installingdeb
packages might stop the script atdpkg configure
prompts. - I initially tried to use
set -i
andset +i
to turn the feature on and off where I needed it, but this doesn't work.
Solution 3:
Your .bashrc
usually starts:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Since your script does not have PS1 set (because it is not interactive), it doesn't reset path because it exits early . To demonstrate, modify your script:
#!/bin/bash
chmod a+x ~/.bashrc
PS1='$ '
source ~/.bashrc
this will now allow your scripts to work with the new .bashrc
.
Note: once your script exits , the env will be set to what it was before starting the script . The changes will be reflected the next time a terminal is started.
Solution 4:
Try:
exec bash
This should reload ~/.bashrc
, ~/.bash_aliases
, etc.
Solution 5:
None of the other methods worked for me [source /path/to/file
vs . ./path/to/file
, alias, etc...], until, thanks to this tutorial I found that using the:
#!/usr/bin/env bash
shebang
instead of the simpler #!/usr/bin/env
one lets arguments pass on to the interpreter, which I think is the key here – see this document for more info.
In any event, if source commands in any form aren't working for you, try checking your shebang, that might be the problem :)