简体   繁体   中英

In bash, either exit script without exiting the shell or export/set variables from within subshell

I have a function that runs a set of scripts that set variables, functions, and aliases in the current shell.

reloadVariablesFromScript() {
  for script in "${scripts[@]}"; do
    . "$script"
  done
}

If one of the scripts has an error, I want to exit the script and then exit the function, but not to kill the shell.

reloadVariablesFromScript() {
  for script in "${scripts[@]}"; do
    {(
      set -e
      . "$script"
    )}
    if [[ $? -ne 0 ]]; then
      >&2 echo $script failed.  Skipping remaining scripts.
      return 1
    fi
  done
}

This would do what I want except it doesn't set the variables in the script whether the script succeeds or fails.

Without the subshell, set -e causes the whole shell to exit, which is undesirable.

Is there a way I can either prevent the called script from continuing on an error without killing the shell or else set/export variables, aliases, and functions from within a subshell?

The following script simulates my problem:

test() {
  {(
    set -e

    export foo=bar
    false
    echo Should not have gotten here!
    export bar=baz
  )}

  local errorCode=$?

  echo foo="'$foo'".  It should equal 'bar'.
  echo bar="'$bar'".  It should not be set.

  if [[ $errorCode -ne 0 ]]; then
    echo Script failed correctly.  Exiting function.
    return 1
  fi

  echo Should not have gotten here!
}

test

If worst comes to worse, since these scripts don't actually edit the filesystem, I can run each script in a subshell, check the exit code, and if it succeeds, run it outside of a subshell.

Note that set -e has a number of surprising behaviors -- relying on it is not universally considered a good idea. That caveat being give, though: We can shuffle environment variables, aliases, and shell functions out as text:

envTest() {
  local errorCode newVars
  newVars=$(
    set -e

    {
      export foo=bar
      false
      echo Should not have gotten here!
      export bar=baz
    } >&2

    # print generate code which, when eval'd, recreates our functions and variables
    declare -p | egrep -v '^declare -[^[:space:]]*r'
    declare -f
    alias -p
  ); errorCode=$?
  if (( errorCode == 0 )); then
    eval "$newVars"
  fi
 
  printf 'foo=%q. It should equal %q\n' "$foo" "bar"
  printf 'bar=%q. It should not be set.\n' "$bar"
 
  if [[ $errorCode -ne 0 ]]; then
    echo 'Script failed correctly.  Exiting function.'
    return 1
  fi
 
  echo 'Should not have gotten here!'
}
 
envTest

Note that this code only evaluates either export should the entire script segment succeed; the question text and comments appear to indicate that this is acceptable if not desired.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM