I have pattern matching problem in case command in bash

I usually use pattern matching in [[ command, but I wanted to use it in case command.

#!/bin/bash
bash -version|head -1
# Test 1:
[[ apple79 == apple@(14|38|79|11) ]] && echo ok 1
# Test2:
case apple79 in apple@(14|38|79|11)) echo ok 2;; *) ;; esac

When I run the above test.sh at terminal with . command everything is normal.

. test.sh
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
ok 1
ok 2

But when I try to run it so:

./t.sh
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
ok 1
./t.sh: line 6: syntax error near unexpected token `('
./t.sh: line 6: `    case apple79 in apple@(14|38|79|11)) echo ok 2;; *) ;; esac'

I have received an error messages for the case command. I have seen some bash pattern matching doc eg.: https://www.linuxjournal.com/content/pattern-matching-bash But I have no any idea for this problem.

Upvotes: 1

Views: 298

Answers (3)

Saboteur
Saboteur

Reputation: 1428

The difference is between interactive and non-interactive shell options. By default extglob are turned off for non-interactive shells, so you can do:

bash -i t.sh

or add

shopt -s extglob

at the beginning of your script

Upvotes: 2

Inian
Inian

Reputation: 85895

The error is most likely because you have turned on extglob option in your current shell. Because sourcing the script takes the current shell's options and extended options, it works when sourcing the script.

But when doing the ./t.sh you are launching an explicit shell which does not have the option turned on by default. Since [[ operator with == turns on extglob by default, it works for the first test but fails for the case statement. To enable the option explicitly in scripts do shopt -s extglob at the top of your script.

As you can see below the pattern works with case only if the option is enabled. Try removing -O extglob from below command and you can see it doesn't work.

bash -O extglob -c 'case apple79 in apple@(14|38|79|11)) echo ok 2;; *) ;; esac'

As far why your attempt didn't work, try adding a line shopt extglob to your t.sh and repeat your tests. You'll notice that when the script is sourced you'll see extglob on and for the executed case get extglob off

Upvotes: 2

chepner
chepner

Reputation: 532418

The extglob option is implicitly enabled inside [[ ... ]] for pattern matching, but you need to enable it explicitly to use it with the case statement.

#!/bin/bash

shopt -s extglob

[[ apple79 == apple@(14|38|79|11) ]] && echo ok 1
case apple79 in apple@(14|38|79|11)) echo ok 2;; *) ;; esac

Upvotes: 3

Related Questions