Why does my LD_LIBRARY_PATH get unset launching terminal?

I have a shell script to set up some environment variables and launch whatever program I send in as an argument:

export PATH=$HOME/local/bin:$PATH
export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH
export TESTER="MY TEST VAR"

$@

When I use this to call bash for example it works:

kjfletch@flatbed:~$ envrun.sh bash
kjfletch@flatbed:~$ echo $LD_LIBRARY_PATH
/home/kjfletch/local/lib:
kjfletch@flatbed:~$ echo $TESTER
MY TEST VAR

When I use it to call a terminal (xterm, aterm, ...) my LD_LIBRARY_PATH gets unset:

kjfletch@flatbed:~$ echo $LD_LIBRARY_PATH

kjfletch@flatbed:~$ echo $TESTER

MY TEST VAR

Why does this happen? How can I stop this? (I am running Debian 5.0)

Update

My terminal is not calling bash as a login:

kjfletch@flatbed:~$ echo $0
bash

My LD_LIBRARY_PATH does not show up in any of the bash startup files (apart from .bash_history and ~/.profile does not exist.):

kjfletch@flatbed:~$ grep "LD" ~/.bash*
kjfletch@flatbed:~$ grep "LD" /etc/bash.bashrc 
kjfletch@flatbed:~$ grep "LD" /etc/profile 

The terminal binary is most likely setgid to group utmp. Setuid and setgid binaries unset LD_LIBRARY_PATH for security reasons; see ld.so(8):

The necessary shared libraries needed by the program are searched for in the following order

  • Using the environment variable LD_LIBRARY_PATH (LD_AOUT_LIBRARY_PATH for a.out programs). Except if the executable is a setuid/setgid binary, in which case it is ignored.

In the terminal (xterm, aterm etc), check how the shell was invoked: A login shell will show "-bash" and a non-login shell will show "bash" when you call echo $0.

$ echo $0
-bash
$ bash
$ echo $0
bash

A login bash shell will read the following in order:

  1. /etc/profile
  2. ~/.bash_profile
  3. ~/.bash_login
  4. ~/.profile

Check if any of these files exist, and if they reset the variable. You'll also have to follow any files these files include.

If bash is not invoked as a login shell, it will still read the below files if is determined to be an interactive shell.

  1. /etc/bash.bashrc
  2. ~/.bashrc

A simple way to determine the kind of bash shell being invoked is to define your .bash_profile and .bashrc, and echo "Login shell" and "Interactive shell" respectively.

Once you know the kind of shell being invoked, you have the option of adding your script to the .bashrc or .bash_profile file in your home directory. Alternatively, you can disable the reset of LD_LIBRARY_PATH.

Note that if your .bashrc or .bash_profile is protected by a guard similar to the one below, you might have to call your script outside of it:

if [ "X$BASH_SOURCED" != "XYES" ]; then
        export BASH_SOURCED=YES

fi

Such guards are normally placed to prevent a script being sourced multiple times in a session.

Edit: If it is proving tedius to track down where the variable is being reset, and you have access to /etc/profile or /etc/bash.bashrc for example, you can temporarily add "set -x" near the top of the script to see all the commands that get executed. The output will be pretty verbose, so first do a "set -x" in your shell and run a few commands so you know what to expect.


bash will use different start-up scripts depending on how it is started. There are seven different ways to start it, but the most important are login shells versus non-login interactive shells.

Check out the bash manual for more details. I would suspect the /etc/profile or the ~/.bash_profile is doing something to reset the LD_LIBRARY_PATH variable.


Edit: I think you have done all you reasonably can to show that bash does not have any startup script that unsets LD_LIBRARY_PATH. It is time to bring out the big guns.

The following command will display the entire environment as each process starts up, from bash to xterm, and anything else that happens to be involved -- you will probably get a large amount of output, so saving the output to a file is a good idea.

strace -v -f -e trace=process -o strace_output.txt envrun.sh xterm

Now, the file strace_output.txt will show each system call made by your script and every child process, and you will be able to see which process was the last to have LD_LIBRARY_PATH before it got removed.


(This question is very old, but I just encountered the same problem, and am documenting the solution for posteriority:)

I've had this problem with GNU screen (the terminal multiplexer), but it can as well happen with a regular terminal. Teddy was right in my case, screen has setguid set.

$ ls -l /usr/bin/screen
-rwxr-sr-x 1 root 84 361016 Mar 30  2011 /usr/bin/screen
      ^

My solution was to save LD_LIBRARY_PATH before execution, and restoring it afterwards. So I created a wrapper ~/bin/screen (put ~/bin on PATH), with the following contents:

#!/bin/bash

# somehow, screen resets LD_LIBRARY_PATH.
# save it here, and restore it in .bashrc
export PRESERVE_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
/usr/bin/screen "$@"

and then made it executable with chmod +x ~/bin/screen. You might have to open a new shell to get it to pick up the wrapper.

Then I added the following to ~/.bashrc . Remember ~/.bashrc gets sourced every time you start bash, unlike ~/.bash_profile which only gets sourced at login (usually at startup, or when you login over ssh).

if [[ "$PRESERVE_LD_LIBRARY_PATH" != "" ]]; then
    export LD_LIBRARY_PATH="$PRESERVE_LD_LIBRARY_PATH"
    #echo "restored LD_LIBRARY_PATH"
    export -n PRESERVE_LD_LIBRARY_PATH
fi

Now screen (or aterm, xterm, ... just substitute it above) should preserve $LD_LIBRARY_PATH as wanted.