1

A recommended pattern that mimics try-catch in bash scripts is to use curly braces. This does not work as expected, though. The following script outputs A B 1. Why is that the case and how must the script be modified to output the intended A C 1?

#!/usr/bin/env bash
set -e

{
  echo "A"
  false
  echo "B"
} || echo "C"

{
  echo "1"
  false
  echo "2"
}
Stefan
  • 207
  • 2
  • 8

3 Answers3

1

There are many issues with the 'set -e' - it does not work well in many error conditions. This has been covered in many posting, just search 'errexit bash'. For example: Bash subshell errexit semantics

At this time, there is no clean solution. However, there are good news. I'm working on a proposed change that will allow the above to work. See discussion in bash-bug archive: https://lists.gnu.org/archive/html/bug-bash/2022-07/index.html And proposal: https://lists.gnu.org/archive/html/bug-bash/2022-07/msg00006.html

Final proposal for the 'errfail' can be found: https://lists.gnu.org/archive/html/bug-bash/2022-07/msg00055.html

I expect to have the solution submitted for review by the bash dev team this week. Hopefully it will get accepted into next bash release.

It will support new 'errfail' option

set -o errfail
{ echo BEFORE ; false ; echo AFTER ; } || echo "CATCH"

and will output: BEFORE CATCH

If you are looking for more fancy solution consider:

alias try=''
alias catch='||'
try {
    echo BEFORE
    false
    echo AFTER
} catch { echo CATCH ; }
dash-o
  • 13,723
  • 1
  • 10
  • 37
  • Great answer! Could you please explain, how the alias solution works? Does it prevent bash from applying the "boolean" logic that disables errexit for the subshell? – Stefan Jul 07 '22 at 11:03
  • Yes, exactly as you said. It also avoid the "boolean" logic associated with '||', '&&', and other related glitches. See reference to latest post (which does include a patch against latest development branch). If you like this approach, consider joining the bash-bug group and providing your view. I believe community support will help. – dash-o Jul 08 '22 at 10:02
  • Note that the alias is simply a fancier option to mimic Python, etc. The actual logic is built into the various bash flow control statements: if, while, for, etc. – dash-o Jul 08 '22 at 10:25
1

A work-around using 2 separate bash invokations:

bash -c 'set -e; echo "A"; false; echo "B"' || echo 'C'

bash -c 'set -e; echo "1"; false; echo "2"'

Or with intendations:

bash -c '
   set -e
   echo "A"
   false
   echo "B"
' || echo 'C'

bash -c '
   set -e
   echo "1"
   false
   echo "2"
'

Output:

A
C
1

Code Demo

anubhava
  • 761,203
  • 64
  • 569
  • 643
0

Just use && and remove this dangerous hardly predictable set -e.

#!/bin/sh

{
  echo "A" &&
  false &&
  echo "B"
} || echo "C"

{
  echo "1" &&
  false &&
  echo "2"
}

Test run it

There is never anything wrong with being absolutely explicit in code. Don't count on the implementation to handle even part of the logic.

This is what set -e is doing. Handles some logic for you, and it does it very differently from what you'd expect it to be most of the time.

So be always explicit and handle error conditions explicitly.

Léa Gris
  • 17,497
  • 4
  • 32
  • 41