Writing try catch finally in shell

后端 未结 6 1003
说谎
说谎 2021-01-30 09:52

Is there a linux bash command like the java try catch finally? Or does the linux shell always go on?

try {
   `executeCommandWhichCanFail`
   mv output
} catch {         


        
相关标签:
6条回答
  • 2021-01-30 10:32

    I found success in my script with this syntax:

    # Try, catch, finally
    (echo "try this") && (echo "and this") || echo "this is the catch statement!"
    
    # this is the 'finally' statement
    echo "finally this"
    

    If either try statement throws an error or ends with exit 1, then the interpreter moves on to the catch statement and then the finally statement.

    If both try statements succeed (and/or end with exit), the interpreter will skip the catch statement and then run the finally statement.

    Example_1:

    goodFunction1(){
      # this function works great
      echo "success1"
    }
    
    goodFunction2(){
      # this function works great
      echo "success2"
      exit
    }
    
    (goodFunction1) && (goodFunction2) || echo "Oops, that didn't work!"
    
    echo "Now this happens!"
    

    Output_1

    success1
    success2
    Now this happens!
    

    Example _2

    functionThrowsErr(){
      # this function returns an error
      ech "halp meh"
    }
    
    goodFunction2(){
      # this function works great
      echo "success2"
      exit
    }
    
    (functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
    
    echo "Now this happens!"
    

    Output_2

    main.sh: line 3: ech: command not found
    Oops, that didn't work!
    Now this happens!
    

    Example_3

    functionThrowsErr(){
      # this function returns an error
      echo "halp meh"
      exit 1
    }
    
    goodFunction2(){
      # this function works great
      echo "success2"
    }
    
    (functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
    
    echo "Now this happens!"
    

    Output_3

    halp meh
    Oops, that didn't work!
    Now this happens!
    

    Note that the order of the functions will affect output. If you need both statements to be tried and caught separately, use two try catch statements.

    (functionThrowsErr) || echo "Oops, functionThrowsErr didn't work!"
    (goodFunction2) || echo "Oops, good function is bad"
    
    echo "Now this happens!"
    

    Output

    halp meh
    Oops, functionThrowsErr didn't work!
    success2
    Now this happens!
    
    0 讨论(0)
  • 2021-01-30 10:39

    I often end up with bash scripts becoming quite large, as I add additional options, or otherwise change them. When a bash-script contains a lot of functions, using 'trap EXIT' may become non-trivial.

    For instance, consider a script invoked as

    dotask TASK [ARG ...]
    

    where each TASK may consists of substeps, where it is desirable to perform cleanup in between.

    In this case, it is helpful to work with subshells to produce scoped exit traps, e.g.

    function subTask (
        local tempFile=$(mktemp)
        trap "rm '${tempFile}'" exit
        ...
    )
    

    However, working with subshells can be tricky, as they can't set global variables of the parent shell.

    Additionally, it is often inconvenient to write a single exit trap. For instance, the cleanup steps may depend on how far a function came before encountering an error. It would be nice to be able to make RAII style cleanup declarations:

    function subTask (
        ...
        onExit 'rm tmp.1'
        ...
        onExit 'rm tmp.2'
        ...
    )
    

    It would seem obvious to use something like

    handlers=""
    function onExit { handlers+="$1;"; trap "$handlers" exit; }
    

    to update the trap. But this fails for nested subshells, as it would cause premature execution of the parent shell's handlers. The client code would have to explicitly reset the handlers variable at the beginning of the subshell.

    Solutions discussed in [multiple bash traps for the same signal], which patch the trap by using the output from trap -p EXIT will equally fail: Even though subshells don't inherit the EXIT trap, trap -p exit will display the parent shell's handler so, again, manual resetting is needed.

    0 讨论(0)
  • 2021-01-30 10:42

    Another way to do it would be:

    set -e;  # stop on errors
    
    mkdir -p "$HOME/tmp/whatevs"
    
    exit_code=0
    
    (
      set +e;
      (
        set -e;
        echo 'foo'
        echo 'bar'
        echo 'biz'
      )
      exit_code="$?"
    )
    
    rm -rf "$HOME/tmp/whatevs"
    
    if [[ "exit_code" != '0' ]]; then
       echo 'failed';
    fi 
    

    although the above doesn't really offer any benefit over:

    set -e;  # stop on errors
    
    mkdir -p "$HOME/tmp/whatevs"
    
    exit_code=0
    
    (
        set -e;
        echo 'foo'
        echo 'bar'
        echo 'biz'
        exit 44;
        exit 43;
    
    ) || {
       exit_code="$?"  # exit code of last command which is 44
    }
    
    rm -rf "$HOME/tmp/whatevs"
    
    if [[ "exit_code" != '0' ]]; then
       echo 'failed';
    fi 
    
    0 讨论(0)
  • 2021-01-30 10:52

    Well, sort of:

    { # your 'try' block
        executeCommandWhichCanFail &&
        mv output
    } || { # your 'catch' block
        mv log
    }
    
     rm tmp # finally: this will always happen
    
    0 讨论(0)
  • 2021-01-30 10:52

    Based on your example, it looks like you are trying to do something akin to always deleting a temporary file, regardless of how a script exits. In Bash to do this try the trap builtin command to trap the EXIT signal.

    #!/bin/bash
    
    trap 'rm tmp' EXIT
    
    if executeCommandWhichCanFail; then
        mv output
    else
        mv log
        exit 1 #Exit with failure
    fi
    
    exit 0 #Exit with success
    

    The rm tmp statement in the trap is always executed when the script exits, so the file "tmp" will always tried to be deleted.

    Installed traps can also be reset; a call to trap with only a signal name will reset the signal handler.

    trap EXIT
    

    For more details, see the bash manual page: man bash

    0 讨论(0)
  • 2021-01-30 10:57

    mv takes two parameters, so may be you really wanted to cat the output file's contents:

    echo `{ execCommand && cat output ; } || cat log`
    rm -f tmp
    
    0 讨论(0)
提交回复
热议问题