88

I've been updating some of the default profile for bash, and saw from the tutorials I was following that I could reload the new profile with the new environment settings by using:

source /etc/bash.bashrc

The only thing is - the new environment variables were only available to my current user - and were ignored when I used sudo. They only became available to sudo when I closed my terminal session and rejoined.

When I try to use:

sudo source /etc/bash.bashrc

I get the error:

sudo: source: command not found

Is there a simple way to load in the new bash profile settings for sudo without having to close the terminal and restart?

-- Initially, I was using some installer scripts which referenced the variables. I found that while they could access the variables when I called the scripts directly (although, this would cause a later problem with creating directories as I needed to be root), calling the install scripts using sudo wouldn't.

I proved this by testing with these simple commands:

echo $ENV_VARIABLE
sudo echo $ENV_VARIABLE

The first would output the variable's value, but the second wouldn't output anything.

1
  • How did you try to use the variables from sudo ? Please note that if you use "sudo command $variable" it will replace the variable from your shell, not from sudo's environment. Jan 10, 2011 at 22:57

8 Answers 8

118

The problem is that source is a bash build-in command (not a program - like ls or grep). I think one approach is to login as root and then execute the source command.

sudo -s
source /etc/bash.bashrc
5
  • 3
    You're right that the problem is that source is a shell builtin. sudo su is a kind of weird way to say it -- better to just say sudo -s which is sudo's own way of saying "start a shell as this user." Your one-line version won't work because each of the commands in it is run by the main user's shell in a separate subprocess.
    – poolie
    Jan 10, 2011 at 22:58
  • 1
    Right. Plus BASH reads /etc/bashrc at login time. So you may as well use 'su' with -, -l, or --login switch in order to get the environment of that user: 'sudo su -' to become root or 'su - $username' to become another user.
    – user8290
    Jan 10, 2011 at 23:21
  • 1
    The "one line" example won't work because su starts a new shell and "source" is run only after it terminates. The first example only works if the second line used inside the root shell.
    – loevborg
    Jan 11, 2011 at 9:41
  • sudo -s is no better than sudo su. It won't have any effect either way.
    – loevborg
    Jan 11, 2011 at 13:58
  • 1
    sudo -s has a similar effect of starting a shell, but to me it seems inelegant to stack two "become another user" commands when one would do.
    – poolie
    Jan 12, 2011 at 2:18
18

The problem is not that source is a shell builtin command. The fact that it is is what's actually throwing you the command not found error, but it doesn't mean it would work if it were.

The actual problem is how environment variables work. And they work like this: every time a new process is started, if nothing happens, it inherits the environment of its parent. Due to this, using a subshell (e.g. typing bash inside a bash instance) and looking at the output of env should give similar results than its parent.

However, due to how sudo works (as stated in its manpage), sudo tries to strip the environment of the user and create a "default" environment for the supplanting user, so that the command run is run as if the user who invoked it had been the calling user (which is the expected behaviour), and thus running nautilus as sudo nautilus should open a folder at the /root folder, and not /home/yourusername.

So:

Doing something like sudo source script.sh and then sudo command, even if it worked, it wouldn't be successful at setting any variable to the later sudo command.

In order to pass environment variables, you can either tell sudo to preserve the environment (via the -E switch; and having appropriate permissions in your sudoers file) and/or setting it for the command as sudo VAR1=VALUE1 VAR2=VALUE2 command.

13

Using bash process substitution you can do:

source <(sudo cat /etc/bash.bashrc)
5
  • 1
    How would this help starting a root shell with the new settings, which is what OP is looking to do?
    – muru
    Jul 30, 2018 at 17:38
  • 3
    The OP was actually asking how to "... reload the new profile ..." from a shell which needs to use sudo to access the profile. The above provides a means to import the profile whilst avoiding the sudo: source: command not found issue mentioned.
    – TomDotTom
    Aug 3, 2018 at 14:25
  • "The only thing is - the new environment variables were only available to my current user - and were ignored when I used sudo."
    – muru
    Aug 3, 2018 at 14:55
  • 1
    This is my favorite answer. It works very well.
    – MountainX
    Nov 1, 2020 at 3:33
  • Worked for me. Great solution. I needed to source a .bash_profile as another user, without being able to su to that user directly. The following worked: source <(sudo -u theuser cat /home/theuser/.bash_profile). Thanks.
    – Matt
    Feb 28, 2022 at 18:52
5

As Marcos says, your main problem here is that source is a shell builtin command that affects only the shell process in which it's run.

The easy solution is to just start a new shell as root, and bash will automatically read /etc/bash.bashrc when it starts. That's as simple as just saying

sudo bash
2

Closing and reopening the terminal should not change things. By default, sudo strips the environment. To disable that, add -E to sudo.

2

The error happens because the binary you are trying to call from command line is only part of the current user's PATH variable, but not a part of root user's PATH.

You can verify this by locating the path of the binary you are trying to access. In my case I was trying to call "bettercap-ng". So I ran,

$ which bettercap-ng
/home/user/work/bin/bettercap`

I checked whether this location is part of my root user's PATH.

$ sudo env | grep ^PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin

So sudo cannot find the binary that I am trying to call from commandline. Hence returns the error command not found.

You can direct sudo to use the current user's PATH when calling a binary like below.

sudo -E env "PATH=$PATH" [command] [arguments]

In fact, one can make an alias out of it:

alias mysudo='sudo -E env "PATH=$PATH"'

It's also possible to name the alias itself sudo, replacing the original sudo.

2

Some UNIX shell does not support source. instead, they support . So try this

. /etc/bash.bashrc

Hope it works

1
  • 2
    That won't work here. It's still a shell builtin, and even if it did work it'd set up an environment that'd immediately vanish as the command finished. Nov 20, 2019 at 8:02
0

It doesn't work because source is a built in command, not a program. I wrote a bash script to force sudo on built in commands:

#!/bin/bash

function forceSudo()
{
    command="${@}"
    file="${@: -1}"
    if ! $command 2>/dev/null
    then
        permission=$(stat -c '%a' $file)
        sudo chmod o+rx $file
        result=$command 2>/dev/null
        sudo chmod $permission $file
        if ! $result
        then
            echo $result
        fi
    fi
}

Save the file as forceSudo and save it in your scripts location, possibly ~/.local/bin. To avoid having to source the file before using the function, add alias forceSudo='unalias forceSudo && . forceSudo && forceSudo "$@"' to ~/.bashrc.

Now you can use forceSudo source /etc/bash.bashrc.

You must log in to answer this question.

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