EMiller
EMiller

Reputation: 2842

Starting screen in detached mode doesn't source environment

I would like to start screensessions in a detached state so that they terminate once the script finishes and so that I can write a script to execute multiple screen sessions without me having to manually, one by one, start each session and then detach, before moving onto to the next screen session.

This script depends on certain environment variables being set. Normally, when I run this script outside of screen, in a regular bash shell, I simply have these environment variables set in my .bash_profile file.

Furthermore, when I start screen in a non-detached state and put in my .screenrc file:

shell -$SHELL

then I also have no problems.

The issue only arises when I perform screen -dm then my script fails to run as the environment I need is not set.

How can I tell screen to refer to the .screenrc file when starting in a detached state such that it ultimately sources my .bash_profile on startup?

UPDATE

When I perform screen -dmL env I can see that some but not all of my environment variables are present.

Upvotes: 5

Views: 3602

Answers (2)

Brian Ephraim
Brian Ephraim

Reputation: 127

No need for ~/.screenrc
Make your ~/.bash_profile one line: source ~/.bashrc
Put your aliases and environemnt variables in ~/.bashrc

In ~/.bashrc, write code like this:

alias myalias="echo ThisWorks"

run_myalias_in_bg_screen (){
    screen -dmS mytestscreen bash -c 'exec bash'
    screen -r mytestscreen -p0 -X stuff "myalias"
    screen -r mytestscreen -p0 -X eval "stuff \015"
}

Now test it out in your terminal

$ run_myalias_in_bg_screen
$ screen -r mytestscreen

Upvotes: 2

ntc2
ntc2

Reputation: 11922

I believe your problem is that when starting screen in detached mode, screen does not start a login shell or an interactive shell, and so your .bash_profile is not sourced (see the "INVOCATION" section of man bash for an explanation of what files are sourced when on start up). Note that the leading - in your

shell -$SHELL

setting means the shell will always be started as a login shell, and so .bash_profile will be sourced.

Some possible solutions to your problem:

  1. don't start screen in detached state. Note that screen terminates when the script finishes when started in the usual way, if the script is given as a command. E.g., for the script test.sh:

    #!/bin/bash
    
    for n in `seq 1 5`; do
      echo $n
      sleep 1
    done
    

    doing screen ./test.sh runs the script and terminates after 5 seconds.

  2. manually source your .bash_profile in the script you're running in screen. I.e. add

    source ~/.bash_profile
    

    to the beginning of your script, MyScript.

Update 1

I still suspect the problem is that your .bash_profile is not being loaded, so let's be sure your .screenrc is being loaded. Try adding

screen touch /tmp/when-was-screen-rc-sourced

to the end of your ~/.screenrc and then do

screen MyScript

and then

ls -lt --full-time /tmp

Try starting screen a few different ways and see if ~/.screenrc is really failing to load.

Similarly, you can add a line

touch /tmp/when-was-bash-profile-sourced

to the end of your ~/.bash_profile to see when that is loaded.

Update 2

Here is an example that shows that screen does run your script when you have the line

screen touch /tmp/when-was-screen-rc-sourced

at the end of your ~/.screenrc.

Here is the test file test.sh:

#!/bin/bash

touch /tmp/when-did-test-sh-start
for n in `seq 1 5`; do
  echo $n
  sleep 1
done
touch /tmp/when-did-test-sh-finish

Here is the evidence. Running

$ touch /tmp/when-did-we-start; screen -d -m ./test.sh; sleep 6; ls -ltr --full-time /tmp | tail -n4

gives output

-rw------- 1 collins collins    0 2013-11-06 14:43:03.643564802 -0800 when-did-we-start
-rw------- 1 collins collins    0 2013-11-06 14:43:03.659565385 -0800 when-was-screen-rc-sourced
-rw------- 1 collins collins    0 2013-11-06 14:43:03.671565892 -0800 when-did-test-sh-start
-rw------- 1 collins collins    0 2013-11-06 14:43:08.707770194 -0800 when-did-test-sh-finish

So, I still think the problem is related to your ~/.bash_profile (or whatever defines your missing env vars) not being loaded.

Update 3

At this point it might be easier to understand exactly what you're trying to accomplish, and then come up with a better way to do it. To do this it would be helpful for you to provide a minimal example script that illustrates your problem (i.e. it works when you run it directly, or manually after starting screen, but not when run directly via screen ./example.sh or screen -d -m ./example.sh).

But, in the mean time, here's another potential workaround (did you ever try my second original suggestion above, of just sourcing your ~/.bash_profile in your script directly?):

Run your script with bash, explicitly making bash interactive and/or a login shell. E.g. for an interactive login shell do

screen -d -m bash -i -I ./MyScript

See here for a nice summary of what files bash loads in what modes. According to man bash, the bash -i -I combination should make bash run your script in interactive login mode, and hence ~/.bash_profile should get sourced.

Upvotes: 3

Related Questions