84

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.

Zanna
  • 70,465
shantanu
  • 8,599

6 Answers6

49

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, installing deb packages might stop the script at dpkg configure prompts.
  • I initially tried to use set -i and set +i to turn the feature on and off where I needed it, but this doesn't work.
31

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'
  • Thanks for your quick reply. Your solution maybe work but i have to edit bashrc file manually to save the line 'aliac brc=....'. I am trying to develop a gui to change environment variable. So i can not edit another computer's bashrc file manually. – shantanu Oct 05 '11 at 15:57
  • 1
    You have to run source ~/.bashrc in the shell of which you want to change the environment. You can not change it from another process. Maybe (globally) adding this alias could be a part of the install process of your GUI. – Florian Diesch Oct 05 '11 at 17:13
  • 3
    so do i put your alias command earlier in the script and then invoke brc when i want to source my .bashrc or I need to put that alias command in a file somewhere? – user137717 Jun 25 '16 at 19:08
  • What I ended up doing is an extension of Florian Diesch's answer. You could just use a multi-line alias: alias brc='chmod a+x ~/.bashrc; source ~/.bashrc' I'm still pretty new, so I'm not sure if this is considered 'poor practice'. It does work though. – A_user_appears Jan 11 '18 at 17:22
21

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.

user32085
  • 731
  • At least since 16.04 and probably before, the default Ubuntu .bashrc uses a more reliable way to check that the shell is interactive. /etc/bash.bashrc still has the PS1 test. – Zanna Dec 15 '18 at 09:03
16

Try:

exec bash

This should reload ~/.bashrc, ~/.bash_aliases, etc.

Alin Andrei
  • 7,348
  • 10
    This replaces the current bash process with a new one. It's not much shorter or easier than using source but destroys any variables and such that the user has set manually - which may or may not what you want. – Florian Diesch Oct 05 '11 at 17:17
  • hold on, in the context of a Shell script with other commands after the bashrc sourcing, do you put the commands that need the new bash state after that exec bash, the way I understand it command after will still be in the same bash settings as before? – tatsu Mar 04 '19 at 10:22
  • 1
    This seems to prevent the rest of my bash script from executing beyond this line. – muad-dweeb Jun 14 '21 at 23:47
  • Does anyone know how we can continue executing the rest of the codes after exec bash? – Hossein Aug 15 '21 at 11:28
3

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

Nikksno
  • 31
0

I just copied the contents of the original ~/.bashrc file, deleted it, created a new ~/.bashrc and pasted the contents. And, it worked.

prs44
  • 23
  • 6