Home > Blockchain >  How does the behavior of a function change if it is within a subshell?
How does the behavior of a function change if it is within a subshell?

Time:06-02

When making functions within a script it bash, it appears that people often have the function run within a subshell, ie

function(){(

)}

instead of

function(){

}

What are the benefit/downsides of using {()} rather than just {} if any?

CodePudding user response:

Parentheses cause the function to run in a subshell, which is a child process isolated from the parent shell. They're useful when you want to make process-wide environmental changes without affecting the behavior of code outside of the function.

Examples include:

  • Changing the current directory with cd does not affect the parent shell. Running cd in a subshell is a cleaner alternative to pushd and popd.

  • Variable assignments are isolated to the subshell. You can temporarily change global settings like $PATH and $IFS without having to carefully save and restore their values before and after.

  • Shell options changed with set or shopt will be automatically restored when the subshell exits. I commonly write (set -x; some-commands) to temporarily enable command logging, for example.

  • Signal handlers installed with trap are only in effect in the subshell. You can install a custom INT (Ctrl-C) handler for the duration of a function, or a custom EXIT handler to run cleanup code when the function returns.

    func() {(
        echo 'entering func' >&2
        trap 'echo exiting func >&2' EXIT
    
        ...
    )}
    
  • If exit is called it won't cause the entire script to exit. This is useful if you want to call exit from several functions down the call stack as a sort of poor man's "exception".

    Or if you want to source a script that might exit, wrapping it in a subshell will keep it from killing your script.

    (
        . ./script-that-might-exit
        echo "script set \$foo to $foo"
        echo "script changed dir to $PWD"
    )
    


Fun fact: Functions don't have to be delimited by curly braces. It's legal to omit the braces and use parentheses as the delimiters:

func() (
    # runs in a subshell
)

CodePudding user response:

If exit is called in a (..) subshell, it will only terminate that expression. Moreover, the code is free to change the values of variables as well as global options (via set); those changes are not seen in the surrounding code and are gone when the expression exits, which can simplify reasoning about the correctness of the code.

When you use (...) inside a function, watch out of this pitfall: a return command inside the (...) won't return from the function; it will just terminate the (...), just like exit. If you have commands after the (...), they will then execute.

  • Related