Bash: Execute script in context of calling shell - bash

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?

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.

Related

What does a Bash command do to the file typed in afterwards?

I just learned that the bash command opens up a new Bash shell inside of whatever shell you're using, and uses the profile of .bashrc for its commands.
When I was installing Laravel earlier this week, I used a bash init.sh command. Now I'm wondering, what exactly did that bash init.sh command do? Why did I need to open a new shell to... execute or open whatever was in init.sh?
Quoting man bash*:
ARGUMENTS
If arguments remain after option processing, and neither the -c nor the -s option has been supplied, the first argument is assumed to be the name of a file containing shell commands. If bash is invoked in this fashion, $0 is set to the name of the file, and the positional parameters are set to the remaining arguments. Bash reads and executes commands from this file, then exits. Bash's exit status is the exit status of the last command executed in the script. If no commands are executed, the exit status is 0. An attempt is first made to open the file in the current directory, and, if no file is found, then the shell searches the directories in PATH for the script.
In other words: bash <file> executes <file> as a Bash script. You will not get a new interactive shell.
Note that this is not the only way to specify which shell (or indeed any command) should be used to execute a script: It's common to use a shebang for that, so that the script can be ‘executed’ by itself.
* The one I had at hand, of Bash v4.3.42.

bash shell in Cygwin

when I am in a Cygwin terminal, I can easily use the "source" command.
For example, let's say I have a file called "my_aliases.sh", that contains the following
#!/bin/bash -f
alias clear='cmd /c cls'
#unalias clear
Then on the Cygwin terminal, I can type
$source my_aliases.sh
And it just works fine, and whenever I type "clear", I can see that it works.
But I don't know why doing the same thing inside another shell script, and calling that shell script doesn't work.
For example, let's say that I have a file called "run_alias.sh", with the following content:
#!/bin/bash -f
#
a=`source my_aliases.sh`
b=`ls -ltr`
echo $a
echo $b
And when I try to run my file
$ ./run_alias.sh
It just doesn't do anything. For example, I can see that the command (b) takes place, but nothing happens for command (a).
But after I run "run_alias.sh", and type "clear", I get the following error:
$ clear
bash: clear: command not found
I even tried to change run_alias.sh as follows:
#!/bin/bash -f
echo `source my_aliases.sh`
But now when run run_alias.sh, and type clear, I get the exact same error message !!!
Any idea how to call the "source" command from some other shell script in Cygwin?
A child process cannot alter its parent's environment.
When you execute the run_alias.sh script, you launch a new bash process, which sources your alias file. Then the script ends, that bash process terminates and it takes its modified environment with it.
If you want your aliases to be automatically available, source it from your $HOME/.bashrc file.
Backticks create a subshell. The changes made to your environment in that subshell do not affect the calling environment.
Id you want your script (run_alias.sh) to have access to the environment in my_aliases.sh, call source directly.
source my_aliases.sh
b=`ls -lrt`
echo $b
and if you want the changes that run_alias.sh makes to its environment to propagate to it's parent, run source on the command line.
$ source run_alias.sh

call "exit" from within shell script

I'm trying to write a simple script (for an embedded system) that mounts an external file from the network and then calls exit on the command line (which exits the busybox terminal and boots the system from the newly-mounted root directory). Problem is, when I call exit from the shell script it exits the script, not the outer terminal. Any hints as to how to send the exit command outside the script?
My code looks something like this:
#!/bin/bash
mount /mnt/root 1.2.3.4:/path/to/external/files -o nolock
exit # exits the script, not the outside filesystem!
exit does indeed exit the current shell. However, running the script creates a new process, and it is that process that exits, not the shell from which you called the script.
You probably want to simply source the file:
$ source myScript.sh
Then myScript.sh is executed in the current shell, rather than a spawned process, and the exit will exit from your current shell (and therefore the terminal itself).
If you want that the scripts exits the outer terminal call it like this:
source your_script
or just
. your_script
where the . is the same as the source command. You can follow this article if you need more information.
Explanation: source will execute the script in the current shell and therefore the exit will be interpreted by the current shell - what will close the pseudo(!) terminal window, if the shell was the first shell in tree

how to write commands into shell script?

I want to write a shell script to execute commands like "export JAVA_HOME=....."
How could I write a script?
I try:
#!/bin/sh
echo "test"
export PATH=$JAVA_HOME/bin:$PATH
export AWS_AUTO_SCALING_HOME=/usr/local/CLI
export PATH=$PATH:$AWS_AUTO_SCALING_HOME/bin
export AWS_CREDENTIAL_FILE=/usr/local/CLI/credential-file-path.template
But the commands are not executed.
But the commands are not executed.
They are executed, but in a sub-shell. The parent shell does not inherit these values.
Instead of executing your script, source it:
source /path/to/myscript.sh
Or
. /path/to/myscript.sh
Further reading: What is the difference between executing a bash script and sourcing a bash script?
How are you executing your script? If you use:
$ script.sh
the environment is set for the duration of the script, but the parent shell is completely unaffected by this (Unix is not DOS!).
To get the results of the commands into your shell, use:
$ . script.sh
or in Bash you can use:
$ source script.sh
(This is a synonym for the . (dot) command, which has been in shells since the Bourne shell. The source command was in C shell first, then added to Bash.)
These read the script into the current process. Any environment variable settings affect the current process. Your profile is effectively read using . $HOME/.profile, for example.
Note that the file for the dotted command is searched for in the directories on $PATH, but the file only needs to be readable, not executable too.
Have you tried setting permission to execute the file??
chmod +x filename

Bash Unix Shell Script to Accept Input and Set System Variables

I'm trying to modify an existing shell script to accept user input and handle some system exports. The below is an excerpt from a larger script. After running this script, I echo $TEST_DIR and I don't get anything back. Any ideas?
#!/bin/sh
if [ -z "$TEST_DIR" ]
then
echo "TEST_DIR was not set, please enter the path: "
read input_variable
export TEST_DIR=$input_variable
exit 1
fi
Save this as script.sh.
#!/bin/bash
if [ -z "$TEST_DIR" ]
then
echo "TEST_DIR was not set, please enter the path: "
read input_variable
export TEST_DIR=$input_variable
fi
And run it like this:
. ./script.sh
Or, equivalently:
source ./script.sh
source runs the script in the current environment and consequently lets you modify the environment in the script. Without it every command, which runs as a child of the shell process, is only given a copy of the current environment.
Note I removed the exit line, as it would terminate the shell in this case.
The problem is that you're running the script in a subshell - it's setting your TEST_DIR properly, but then the shell exits, and the parent shell doesn't keep the change.
You might be better off making this a function you can source from the parent shell. Shell scripts can't modify the environment of the calling shell, but a function can modify the shell it's executing in.
You probably don't want to do exit 1; that is used to indicate failure. You'd use exit 0 to indicate success — but, as described below, you don't want to do that, either, in this case.
The other problem is that if you run the script as child process, it cannot affect the environment of the parent process.
To work around that, in POSIX shells, you need to use:
. your_script.sh
or, in bash, you can also use:
source your_script.sh
The script does not have to be executable, just readable, and will be searched for on $PATH unless you specify a name containing a slash, just like other commands.
And, when you do the . or source, you definitely do not want any exit in the script because that will cause the main shell to exit. The shell reads the file as if you were typing it at standard input (more or less), so an exit that's executed will exit the shell.

Resources