0

So I'm trying to use ;;& in a bash case statement and I'm getting syntax errors.

(macOS 10.14.5, Darwin 18.6.0)

The back story is that I have some scripts that set up unit tests. Different tests need slightly different data sets to work on, so I wrote (essentially) the following (with the details removed, as it doesn't seem to matter):

case $TEST in
    ( 1 )
        # no setup needed
        ;;
    ( 2 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 )
        # these tests need a simple set of captured data
        echo "Capture 1 2 3"
        ;;&
    ( 12 )
        # in addition, test 12 needs some unique data
        echo "Capture 4 non duplicate"
        ;;
    ( 3 | 5 )
        # these tests need data captured in seperate operations
        echo "Capture 1"
        echo "Capture 2"
        echo "Capture 3"
        ;;
esac

When I run this, I get the following error:

Tests/prepare.sh: line 26: syntax error near unexpected token `&'
Tests/prepare.sh: line 26: `        ;;&'

According to man bash:

If the ;; operator is used, no subsequent matches are attempted after the first pattern match. Using ;& in place of ;; causes execution to continue with the list associated with the next set of patterns. Using ;;& in place of ;; causes the shell to test the next pattern list in the statement, if any, and execute any associated list on a successful match.

My interpretation is thus: using ;; is essentially a break that skips over all subsequent patterns in the statement. A ;& is essentially a no-op and just falls through to the next list (ignoring the pattern), and the ;;& continues testing patterns starting with the next one.

I've tried using all ;& and ;;& but get a similar result. Given that bash dates to the 1980's, I'm shocked this does't work. So I assume I'm just missing something, but I can't figure out what.

I can work around this for now (by duplicating the code in some steps so all patterns are unique), but this still haunts me and I would love to know the answer.

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
  • Remove `&` from your code. – Cyrus Jun 01 '19 at 18:49
  • Oh, and before someone complains about the leading parentheses: I have always hated the habit of omitting the optional opening `(` in case statements. I think it makes them harder to read. Nevertheless, it doesn't matter. If you remove the opening parens, you get the same error. – James Bucanek Jun 01 '19 at 18:49
  • @Cyrus ... then the code in case `( 12 )` doesn't execute. Which is the whole point of this question. – James Bucanek Jun 01 '19 at 18:50
  • 3
    This code needs bash 4.0 or newer (they get much newer; current is 5.0). MacOS ships an ancient bash 3.2.x release because they aren't willing to comply with GPLv3 licensing terms. Install a newer one with Nix (my preference), MacPorts, Homebrew, etc. And in the future, include output of `echo "$BASH_VERSION"` in your questions. – Charles Duffy Jun 01 '19 at 18:52
  • Thanks @CharlesDuffy! I guess I'll file a bug report against the man page... – James Bucanek Jun 01 '19 at 18:53
  • Yes, works fine with bash 4.3.48. – Cyrus Jun 01 '19 at 18:54
  • See https://wiki.bash-hackers.org/scripting/bashchanges, listing that as a feature introduced in 4.0-alpha. – Charles Duffy Jun 01 '19 at 18:55
  • See also the official release notes at https://tiswww.case.edu/php/chet/bash/NEWS (grep for `;;&`). – melpomene Jun 01 '19 at 18:55
  • If you have a man page for a newer version, I wonder if you have that version installed, but have your script starting with `#!/bin/bash` (so it always uses the OS-vendor-provided copy in `/bin`), not `#!/usr/bin/env bash` (which would make it use the first one in the PATH, that typically being your Nix/MacPorts/Homebrew/etc. version)? – Charles Duffy Jun 01 '19 at 18:58
  • @CharlesDuffy that's entirely possible. I have `macports` installed on my development machine, so that could be the source. I'll need to check one of my plain-vanilla test machines to see what their man page says... – James Bucanek Jun 01 '19 at 19:02
  • Incidentally, that speaks to one of the reasons I prefer Nix -- you can have different environments with different sets of packages overridden/visible, so when you're developing for project-X, you can have only project-X-relevant software versions added to your environment (and not even the indirect dependencies of those items, since they're retrieved from hash-addressed store locations, not added to your PATH unless requested themselves). – Charles Duffy Jun 01 '19 at 19:05
  • @CharlesDuffy thanks for the suggestion, I will take some time to check out Nix. – James Bucanek Jun 01 '19 at 19:09

0 Answers0