Baldrick
Baldrick

Reputation: 11002

Bash: Execute script in context of calling shell

My understanding is that when I execute a script inside a BASH shell using syntax like $ ./myscript.sh a sub-shell is started and the code runs in that shell, with STDOUT and STDERR output being printed on my shell, STDIN is taken from my shell. This is how script are interactive.

The top line of the file "myscript" is #!/bin/bash, this states the interpreter to be used to execute the syntax within the script file.

If I use the syntax source myscript.sh the code in my script is "pulled" in to my current environment and executed there, rather than in a sub-shell. I can't make the following code run in a script that I call with $ ./myscript.sh and effect my current shell:

#!/bin/bash

PS1='`
  if [ $? -eq 0 ];
    then echo -n "\[\033[00;35m\]\u\[\033[01;32m\]@\[\033[00;35m\]\h\[\033[00;32m\](\[\033[01;35m\]\W\[\033[01;32m\])\[\033[00;32m\]\$";
    else echo -n "\[\033[00;35m\]\u\[\033[01;31m\]@\[\033[00;35m\]\h\[\033[01;31m\](\[\033[35m\]\W\[\033[31m\])\[\033[00;31m\]\$";
  fi`\[\033[0m\]'

If I drop the #!/bin/bash and use source this script changes my command prompt. Can it be arranged in a script in such a fashion that I can call it with $ ./myscript.sh and it will make the change to my current shell, not the sub shell?

Upvotes: 3

Views: 6315

Answers (2)

chuckj
chuckj

Reputation: 155

I'm not quite sure what you're trying to do, so I don't think I can solve your problem (I don't know how $? is being set). That said, what I just discovered today may help people with similar issues.

The OP's script fails its purpose because the changes it attempts to apply are lost when the subshell exits. I've struggled with this several times before, and was again wrestling with it today. I came up with a different approach, rewriting the script to generate but not apply the arguments.

To address the OP's difficulty, create the following script which follows the spirit of the OP's script (I took liberties with the prompt strings and with the conditional statement):

#!/usr/bin/env bash                                                             
# file: setps1
                                                                                
if [ "$1" -eq 0 ]; then                                                         
    echo -n $'\e[35;1m\\u\e[m@\e[32;1m\\h\e[m(\e[32;1m\\W\e[m)\$ '              
else                                                                            
    echo -n $'\e[35;1m\\u\e[m@\e[31;1m\\h\e[m(\e[31;1m\\W\e[m)\$ '              
fi            

Then call it with:

PS1=$( ./setps1 1 )

Note that this also works for commands requiring multiple arguments. In my case, the script originally called enable with three computed arguments and it failed in the familiar way. I rewrote the script to only output the three computed arguments and installed the script in /usr/local/bin for easy access. Using the script to supply the arguments to enable without having to supply complicated paths makes using my builtin more user-friendly.

Upvotes: 0

choroba
choroba

Reputation: 241848

Once you have called a script without source, it is running in a subshell and there is no way to change the environment of the parent shell.

You can source a script with a shebang line. It is simply ignored when sourced.

Upvotes: 7

Related Questions