How to exit source Bash script

I have a bash script that is received. When this script is connected, it runs the function in a Bash script. This function should abort the script if a certain condition is met. How can this be done without completing the shell in which the script is located?

To be clear: I want the completion action to be completed by a function in the original shell of the script, and not in the main body of the original shell of the script. The problems that I see is that return simply returns from the function to the main part of the script, and exit 1 terminates the calling shell.

The following minimal example illustrates the problem:

 main(){ echo "starting test of environment..." ensure_environment echo "environment safe -- starting other procedures..." } ensure_environment(){ if [ 1 == 1 ]; then echo "environment problemm -- terminating..." # exit 1 # <-- terminates calling shell return # <-- returns only from function, not from sourced script fi } main 
+5
source share
5 answers

This is a recipe for how you can achieve your goal with your approach. I will not write your code for you, just tell how it can be done.

Your goal is to set / change environment variables in the current bash shell, effectively using a possible complex shell script. Some component of this script may decide that the execution of this script source should stop. The tricky part is that this solution does not have to be at the top level, but can be located in a nested function call. return does not help, but exit completes the source shell, which is undesirable.

Your task is simplified thanks to your statement:

the additional complexity that I really cannot include in the minimum example makes it very desirable to centralize the completion procedure in a function.

Here's how you do it:

Instead of looking for your real script, which determines which environment should be installed (" realscript.bash "), you use another script, " ipcscript.bash ".

ipcscript.bash establish some interprocess communication. It may be a channel on some additional file descriptor that you open with exec, it may be a temporary file, it may be something else.

ipcscript.bash will run realscript.bash as a child process. This means that the environment changes that realscript.bash does first only affect the environment of this bash child process. By running realscript.bash as a child process, you will be able to stop execution at any nested level with exit without terminating the source shell.

Your exit call will live, when you write, in a centralized function called from any level when it is decided to stop execution. Now, before completing the shutdown function, it is necessary to write the current environment to the IPC engine in a suitable format.

ipcscript.bash will read the environment settings from the IPC engine and play all the settings in the search process.

+2
source

You can return from the original shell script. POSIX Specification

So, if you cannot return from the function directly to get what you want, you can return from the main body of the script if your function returns a non-zero value (or another consistent value).

For instance:

 $ cat foo.sh f() { echo in f " $@ " } e() { return 2 } f 1 e f 2 if ! e; then return fi f 3 $ . foo.sh in f 1 in f 2 
+7
source

How about this: call everything through a simple shell, here is "ocall", which supports global state, here is "STILL_OK"

 STILL_OK=true ocall() { if $STILL_OK then echo -- " $@ " # this is for debugging, you can delete this line if " $@ " then true else STILL_OK=false fi fi } main(){ ocall echo "starting test of environment..." ocall ensure_environment ocall echo "environment safe -- starting other procedures..." } ensure_environment(){ if [ 1 == 1 ]; then ocall echo "environment problemm -- terminating..." # exit 1 # <-- terminates calling shell return 1 # <-- returns from sourced script but leaves sourcing shell running fi } ocall main 
+2
source

It's impossible.

If you use a script, it (for the aspects under consideration) is like entering each line one by one in the shell of the call (source). You want to leave a scope (source script) that does not exist, so you cannot leave it.

The only way I can think of is to pass an exit request to the calling function and test it:

 main() { echo "starting test of environment..." [ "$(ensure_environment)" = "bailout" ] && return echo "environment safe -- starting other procedures..." } ensure_environment() { if [ 1 == 1 ]; then echo "bailout" return fi } main 

What you ask for is usually not possible in other languages. Usually, each function can only end (returning), and not a wider specific area outside itself (for example, the script in which it is located). An exception to this rule is handling exceptions with try / catch or similar.

Also consider the following: if you use this script, shell functions become known in the source shell. Therefore, you can call them later. Then (again) there is no scope, the function may end.

+2
source

Sometimes I write a script that has convenient functions that I want to use outside of the script. In this case, if the script is executed, then it does its thing. But if the script source is received, it just loads some functions into the source shell. I use this form:

 #!/bin/bash # This function will be sourcable foo() { echo hello world } # end if being sourced if [[ $0 == bash ]]; then return fi # the rest of the script goes here 
0
source

Source: https://habr.com/ru/post/1236705/


All Articles