3

The following switch statement has strange behavior:

3)
        if [ $state -ne $last_state ]
        then
            echo "state: $state"
        fi

        stty -F $SERIAL $BAUD -echo igncr
        echo "befor cat"
        {
            cat -v $SERIAL >> $USBDRIVE/gpsData_$filecounter.txt && echo "after cat"
        } || {
            echo "catch"
            state=0
            last_state=3
            ((filecounter++))
        }           
        ;;

I thought, that when the cat command fails while is beeing excecuted, "after cat" will be written and than the part after || will be excecuted. But when I look at the output, it seems that after echoing "after cat" a break happen so that the actual state does not change and will be entered one more time. Then stty fails, too (becaus the serial adapter is missing). After that, the cat command againt fails at the beginning but now enters the "catch" block....

Here is the relevant output:

pi@rpi ~/serial_logger $ ./serial_logger.sh
serial adapter found: ttyUSB0
state: 1
USB-Storage found: usb0
state: 3
before cat
after cat    #here should be entered state 0
state: 3
stty: /dev/ttyUSB0: No such file or directory
before cat
cat: /dev/ttyUSB0: No such file or directory
catch
state: 0
USB-Storage found: usb0
state: 2

What am I doing wrong?

Eric Leschinski
  • 123,728
  • 82
  • 382
  • 321
Rush
  • 31
  • 1
  • According to your current logic, if `after cat` is echoed, that means that `cat` exited successfully. – Tom Fenech Mar 29 '15 at 13:05
  • but when I comment '&& echo "after cat"' the behaviour remains the same – Rush Mar 29 '15 at 13:12
  • As long as the `cat` succeeds (which it appears to be doing), removing the `echo` won't change much (I would expect it to succeed too). – Tom Fenech Mar 29 '15 at 13:21
  • ok. when the cat command starts while the serial adapter is connected it has succeeded. And when I disconnect the adapter while cat has already started and is running, it has succeeded, too? – Rush Mar 29 '15 at 13:40

1 Answers1

2

Why it doesn't work

In your example, the cat succeeds which is why "after cat" is printed and the "catch group" is not entered.

I thought, that when the cat command fails while is beeing excecuted, "after cat" will be written

This assumption is wrong, "after cat" will be written only if cat succeeds because you used the && operator.

and than the part after || will be excecuted.

Note that there is no such thing as a "groupfail" which would allow you to actually emulate try/catch behaviour in Bash using command groups ({ [...] }). Consider this example with multiple lines inside your group:

{
  cmd1
  cmd2
} || { # catch block

As long as cmd2 succeeds, your program will not enter the catch block, even if cmd1 fails.

How to emulate try/catch

You could however use the && operator to emulate try/catch behavior:

cmd1 && cmd2 && cmd3 || { # catch block

This could also be written as

{ cmd1 && cmd2 && cmd3 ; } || { # catch block

You see that however you do it, the syntax is a little clumsy.

Maybe this related stackoverflow question can help you too.

Other error handling mechanisms

Last, but not least, two common Bash error handling mechanisms should be mentioned:

  • Registering a signal handler for the ERR signal causes Bash to call a function whenever a command returns a non-zero exit status:

    trap error_handler ERR
    
    function error_handler() {
      echo error
    }
    
  • Setting the errexit shell option causes your program to terminate as soon as a command returns a non-zero exit status (signal handlers are still executed):

    set -e
    
Community
  • 1
  • 1
Michael Jaros
  • 4,262
  • 1
  • 19
  • 36
  • ok. But when I use '{ cmd1 && cmd2 && cmd3 ; } || { # catch block', the catch block will also only excecuted if cmd1, and only cmd1 fails. Am I right ? – Rush Mar 29 '15 at 15:46
  • @Rush: No, the catch block will be entered as soon as one of the commands fails. The remaining commands will not be executed. The catch block will not be entered if all commands succeed. – Michael Jaros Mar 29 '15 at 15:49
  • Yes I see. But the catch-block will not be executed immediately. This happens only when the cat command has been started correctly. That means that the serial adapter was plugged in. If I run the cat command without plugged serial adapter, the catch-block is executed immediately – Rush Mar 29 '15 at 16:15
  • @Rush: I'm not sure I understand :-) If your `cat` succeeds, then the catch block will _not_ be entered. If your `cat` fails, it _will_ be entered immediately. – Michael Jaros Mar 29 '15 at 16:30
  • Ok, maybe I first try to explain what is my definition of an succeded and unsucceeded execution: The exit-code of an command tells me if an command was successful or not. 0 means successful, 1 unsuccesful. The code is the exit-code of an command, in this case the cat-command. And when we talking about an exit-code, we also talking about an command that has endet, right? That mean that I can not get an exit-code, while the cat-command is still writing stuff from the serial converter in my file. But: When I disconnect the serial converter, the cat command should give me some exit-code != 0 – Rush Mar 29 '15 at 16:51
  • and then the catch-block should be executed. But this is not happening. When I disconnect the converter, cat throw an error "cat: /dev/ttyUSB0: No such file or directory" and do NOT enter the catchblock immediately. When I start the cat-command "cat /dev/ttyUSB0 >> /file" while the serial adapter is not connected, then the catch-block is executed immediately. – Rush Mar 29 '15 at 16:54
  • @Rush: OK I see. Your definition of success is the same as mine, but your `cat` seems to succeed when you unplug your converter (it probably just receives an `EOF` from `/dev/ttyUSB0`). I'm not sure how that fits to the message "cat: /dev/ttyUSB0: No such file or directory". However I'm pretty sure that this is not a Bash problem. Have you tried calling `cat` from the command line and then using `echo $?` to check exit status? – Michael Jaros Mar 29 '15 at 17:12
  • @Rush: Well, there you've got it: Your `cat` returns 0 when you disconnect your adapter. It seems that the usb-serial driver does not consider this an error. There is nothing strange about the shell's behavior in that case. – Michael Jaros Apr 03 '15 at 00:48