Differences between revisions 14 and 16 (spanning 2 versions)
Revision 14 as of 2013-01-14 22:03:43
Size: 1555
Editor: ormaaj
Comment: Stupid mksh. Why the does shift throw fatal errors when POSIX doesn't require it to?!? Add "command" workaround (POSIX doesn't require that either, but it works everywhere except mksh).
Revision 16 as of 2022-11-23 19:29:49
Size: 1777
Editor: GreyCat
Comment: extglobs are only on by default inside [[ ]] in bash 4.1+
Deletions are marked like this. Additions are marked like this.
Line 7: Line 7:
   case "$var" in    case $var in
Line 15: Line 15:
   ${BASH_VERSION+shopt -s extglob}
Line 21: Line 20:
Extended globs are turned on by default inside the `[[` command in bash 4.1 and newer. If you need to target an older version of bash, you will need to turn them on in your script (`shopt -s extglob` outside of all functions or compound commands).
Line 23: Line 24:
    # bash/ksh93/zsh (w/ emulate ksh) #!/usr/bin/env bash
# bash/ksh93
Line 25: Line 27:
    # usage: pmatch string pattern [ pattern ... ]
    function pmatch {
        ${1+typeset x=}"${1-false}" &&
        while command shift; do
            [[ $x == $1 ]] && return
        done 2>/dev/null
        return 1
    }
[[ -v BASH_VERSION ]] && shopt -s extglob
Line 34: Line 29:
    var='foo bar'
    if pmatch "$var" foo bar baz foo\* blarg; then
        : ...
    fi
# usage: pmatch string pattern [ pattern ... ]
function any {
    [[ -n $1 ]] || return
    typeset pat match=$1
    shift

    for pat; do
        [[ $match == $pat ]] && return
    done

    return 1
}

var='foo bar'
if any "$var" '@(bar|baz)' foo\* blarg; then
    echo 'var matched at least one of the patterns!'
fi
Line 51: Line 60:
    ${BASH_VERSION+shopt -s extglob}

I want to check if [[ $var == foo || $var == bar || $var == more ]] without repeating $var n times.

The portable solution uses case:

   # Bourne
   case $var in
      foo|bar|more) ... ;;
   esac

In Bash and ksh, Extended globs can also do this within a [[ command:

   # bash/ksh
   if [[ $var == @(foo|bar|more) ]]; then
      ...
   fi

Extended globs are turned on by default inside the [[ command in bash 4.1 and newer. If you need to target an older version of bash, you will need to turn them on in your script (shopt -s extglob outside of all functions or compound commands).

Alternatively, you may loop over a list of patterns, checking each individually.

# bash/ksh93

[[ -v BASH_VERSION ]] && shopt -s extglob

# usage: pmatch string pattern [ pattern ... ]
function any {
    [[ -n $1 ]] || return
    typeset pat match=$1
    shift

    for pat; do
        [[ $match == $pat ]] && return
    done

    return 1
}

var='foo bar'
if any "$var" '@(bar|baz)' foo\* blarg; then
    echo 'var matched at least one of the patterns!'
fi

For logical conjunction (return true if $var matches all patterns), ksh93 can use the & pattern delimiter.

    # ksh93 only
    [[ $var == @(foo&bar&more) ]] && ...

For shells that support only the ksh88 subset (extglob patterns), you may DeMorganify the logic using the negation sub-pattern operator.

    # bash/ksh88/etc...
    [[ $var == !(!(foo)|!(bar)|!(more)) ]] && ...

But this is quite unclear and not much shorter than just writing out separate expressions for each pattern.


CategoryShell

BashFAQ/066 (last edited 2022-11-23 19:29:49 by GreyCat)