Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I use screen on a daily basis for my terminal needs and I'm quite happy with it. Recently, though, I made some updates to my bash configuration files and I noticed that I was setting various PATH elements (PATH, MANPATH, INFOPATH, etc) in 2 places. I modified the files to be what they should be and now all of my environment variables get set once in .bash_profile. Herein lies my problem.

Apparently, the reason I was setting them in two places was because of screen. screen appears to only execute .bashrc and does not appear to inherit my PATH or any other environment variables correctly from my original bash shell. Because it only executes .bashrc and I now set my variables in .bash_profile only, I get an incomplete PATH.

My question, then, is how to get my environment variables into screen without the duplication. Reading through the Bash docs seems to indicate that it could be the kind of shell that screen uses to log in, i.e. a non-login interactive shell but I couldn't figure out how to force screen to use a particular kind of shell, only the shell to use via -s /bin/bash.

You can peruse my config files at my GitHub page. This is the commit commit that broke screen.

EDIT: I'm using Screen version 4.00.03 (FAU) 23-Oct-06 and I tend to invoke it by screen -h 50000

EDIT: I've now been able to test this on Cygwin (CYGWIN_NT-5.1 1.7.1(0.218/5/3) i686, Screen version 4.00.03 (FAU) 23-Oct-06) and it exhibits different behavior than on my Mac.

The specific behavior that I've now discovered is that in Cygwin the changes that I make to PATH in .bash_profile are duplicated upon entering screen and then successive creation of screen windows do not duplicate the path but do re-source .bash_profile.

To illustrate the behavior I'm talking about:

Output from a fresh terminal:

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

Output from the first invocation of screen:

[~]$ screen -h 50000 -s -/bin/bash

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man:/home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man:/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

Subsequent calls to C-a c:

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man:/home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man:/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

You can see

share|improve this question
    
The duplication is because you have bash configured to unconditionally add these entries with it is a ‘login’ shell, and you are telling screen to invoke bash as a ‘login’ shell. I have rewritten my answer to try to address the general issues of shells, screen, and environment variables. –  Chris Johnsen Mar 2 '10 at 2:54

6 Answers 6

Whenever I have some problem like that I create a file $HOME/.debug and in all of the files sourced/executed during login/shell invocation (e.g. ~/.bashrc, ~/.bash_profile, ~/.profile, /etc/bashrc, etc) I have as the first line

test -f $HOME/.debug && echo $HOME/.bashrc 1>&2

or similar. For specific debugging you can also add things like

test -f $HOME/.debug && echo PATH now equals $PATH 1>&2

This way you can be 100% absolutely certain what files that are or not are used.

The redirect to stderr is important, you do not want something messing up stdout in many situations.

share|improve this answer

The last time I saw a similar issue, I solved it by using screen -l when starting screen.

You can use the -l option when invoking screen (turn login mode on; also controlled by the deflogin and login commands in .screenrc) to set whether screen should log the window in by default (adding/removing the /etc/utmp entry).

Login mode is on by default, but that can be changed at compile time. If screen isn't compiled with utmp support these commands are not available.

I don't seem to need the -l mode in Debian Lenny's default screen (v4.0.3); it seems to be on by default. My ~/.profile and ~/.bashrc are getting read correctly. How are you invoking screen? What version are you using?

share|improve this answer
    
tho under this theory, screen -ln should not run my ~/.profile, and it still gets run. so try the -l flag, but this probably isn't the right answer. will leave it here for the moment. –  quack quixote Feb 27 '10 at 17:12
    
It seems that -l only controls whether screen adds an entry to the utmp file, not whether it invokes new shells with their own -l option or uses the exec-with---prefix custom. –  Chris Johnsen Feb 27 '10 at 19:41

screen and Environment Variables

By default, screen passes along to its shells (and other processes) whatever environment variables it had when the session was started (i.e. reconnecting does not change which environment variables are given to new shells). But because both screen and shells' configuration files commonly change environment variables, there are many places where unexpected changes can be introduced. There are a few variables, like TERM, that screen it almost always changes, but these are generally required for the functionality that screen provides.

Let's say that neither your shell's configuration, nor screen's configuration will modify a variable named FOOBAR (fairly likely, all in all). If you start a session with FOOBAR=foo screen, then all the shells created in that session will have an environment variable named FOOBAR with a value of foo.

Things get more complicated for variables that either screen or your shell might modify.

Missing Settings When Using screen

Login Shells

If you find that some settings are missing in shells started by screen, it may be because your shell is configured only to update those settings for ‘login’ shells. Most shells understand a special convention (in C: **argv == '-') that screen can be configured to use.

Per the screen documentation:

shell command

Set the command to be used to create a new shell. This overrides the value of the environment variable $SHELL. This is useful if you'd like to run a tty-enhancer which is expecting to execute the program speci- fied in $SHELL. If the command begins with a '-' character, the shell will be started as a login-shell.

To have screen start shells as ‘login’ shells, start screen with screen -s -/bin/bash, or add this line to your .screenrc:

shell -/bin/bash

Adjust for the path to whatever shell you happen to be using.

screen Configuration

Missing or reset environment variables could also be due to setenv and unsetenv commands in a screen configuration file. You will have to check both the .screenrc in your home directory and whichever file your compilation of screen is using as the ‘system screenrc’ (you might try a command like strings "$(which screen)" | fgrep -i screenrc to find the pathname that was configured at compile time–it is usually /etc/screenrc for a system-installed screen; add-on installations will probably use some other pathname). You can use SCREENRC=/dev/null SYSSCREENRC=/dev/null screen to temporarily avoid these settings files, but there is a compile-time option that prevents the effective use of SYSSCREENRC (presumably so that system administrators can force some bit of initial configuration).

Duplicate Settings When Using screen

It is fairly common to add items to an environment variable like PATH in a shell's configuration file(s) so that the updated value is available to normal shell sessions (e.g. xterm or other terminal windows, console sessions, etc.). If such items are added in a shell's per-shell configuration (or, if you are using the -/path/to/shell setting described above, in the shells per-login configuration) then the shell started by screen will likely have multiple copies of the added items.

One strategy to avoid this is to put all additions to variables like PATH in the per-login configuration of your shell and avoid using the -/path/to/shell shell setting with screen.

Another strategy is to only conditionally add the new items to the variable. Depending on the shell, the code to do this can be a bit complicated, but it can usually be encapsulated in a shell function for easy use.

Yet another strategy is to always start with a fixed value in your configuration files. This can sometimes cause problems when moving your configuration files from system to system when the default values might vary significantly.

Diagnostics

If you can not directly spot where a particular modification is happening, you can try the following to track down where the change is happening.

Check the current value in your initial shell:

echo "$PATH"

Check how the shell itself modifies the value when a sub-shell is created:

/bin/bash -c 'echo "$PATH"'

Check how the shell modifies the value when a ‘login’ sub-shell is created:

perl -e '$s=shift;exec {$s} "-$s", @ARGV or die "unable to start shell"' /bin/bash
echo "$PATH"
exit

Check how screen modifies the value:

printf '#!/bin/sh\nl=/tmp/echo-var.log;rm -f "$l"; echo $PATH >"$l"' >/tmp/echo-var &&
chmod a+x /tmp/echo-var &&
screen -s /tmp/echo-var &&
cat /tmp/echo-var.log
share|improve this answer
    
This solves part of my problem. Unfortunately it doesn't go the full way. Now, screen is working fine run with screen -s -/bin/bash but it doesn't behave as I've come to expect it to behave under Cygwin on my work machine. On that machine, I run screen -h 50000 and it simply inherits my PATH without actually sourcing the file again. This runs both every time I launch a new window. –  Tim Visher Feb 27 '10 at 19:56
    
The environment of the screen process should always be inherited by any its its children (except for stuff like TERM that it might override). Try FOOBAR=baz screen and check echo $FOOBAR in the shell windows from screen and screen -s -/bin/bash. Both variations should have FOOBAR = baz. If your PATH is being modified, then you will have to track down what is doing it. Try SYSSCREENRC=/dev/null SCREENRC=/dev/null screen, if that lets your PATH through, then it is probably a setenv PATH in /etc/screenrc or ~/.screenrc. Otherwise it is something your .bashrc is doing. –  Chris Johnsen Feb 27 '10 at 20:58
    
I have done a large rewrite of / addition to my answer. –  Chris Johnsen Mar 2 '10 at 2:55

There's nothing wrong with sourcing your .bashrc from within .bash_profile. If you are only using your machine locally your .bash_profile will in most cases only be sourced when you do your initial login (there are obviously other times it gets sourced).

I organize my files so that if I want something to be done only when I login, I put the information in .bash_profile and for everything else I put them in .bashrc. PATH is one thing I put in my .bashrc, and I source .bashrc in my .bash_profile.

share|improve this answer
    
Would you be comfortable posting your .bashrc and .bash_profile files somewhere so that I could see them? The problem I ran into while doing something similar was that PATH would grow every time I would create a new screen instance because it would inherit the old PATH and then re-add everything again. –  Tim Visher Feb 28 '10 at 0:49
    
Sorry Tim, I didn't see this... I've changed a lot of things around so they won't make a lot of sense, but this is basically what I do. # .bash_profile if [ -f ~/.bashrc ]; then . ~/.bashrc fi Then I put everything else in .bashrc, except for things that I want to start when I first login, which also go in .bash_profile. PATH is handled in .bashrc as a series of lines instead of one path definition like most do export PATH=/path/to/binaries1:$PATH export PATH=/path/to/binaries2:$PATH –  user26918 Apr 18 '10 at 19:24

The problem lies with launchd behavior on Leopard. See this MacPorts bug report for screen on Leopard to see why it's not going to ever be fixed unless you can somehow backport Snow Leopard's launchd.

https://trac.macports.org/ticket/18235#comment:26

share|improve this answer

You can stay with .profile since system does not touch bashrc (like graphics session) Now you simply have two different sets of environment - one from .profile, other for bash from .bashrc.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.