0

I am trying to match using a glob pattern. But it is failing when using myfun 12.

dgt='^+([0123456789])$'
[[ "$1" == $dgt  ]] && echo "SUCCESS" || echo "FAILURE"
2
  • It's unclear what you want to do and what your example should print. You have an expression that looks like a mix between an extended globbing pattern and a regular expression, but you try to use it as if it was a globbing pattern.
    – they
    Dec 23, 2021 at 17:38
  • I want to match positive integers such as 12, 345, 23456. dgt is not matching if $1=23.
    – Veak
    Dec 23, 2021 at 17:41

2 Answers 2

4

Your pattern, ^+([0123456789])$, is a mix of an extended globbing pattern and a regular expression. A globbing pattern does not need to be anchored explicitly, as it is always anchored anyway. Therefore, a globbing pattern starting with ^ and ending with $ would match those literal characters at the start and end of a string. If you want to use a globbing pattern and don't want to match ^ at the start and $ at the end, remove these.

You will end up with the following code:

#!/bin/bash

# Bash releases earlier than 4.1 needs to enable the extglob shell
# option.  For release 4.1+, the pattern used in [[ ]] is assumed
# to be an extended globbing pattern.
#
# shopt -s extglob

pattern='+([0123456789])'

if [[ $1 == $pattern ]]; then
   echo 'contains only digits'
else
   echo 'contains non-digit or is empty'
fi

In a shell with no extended globbing patterns, it's easier to match non-digits:

#!/bin/sh

case $1 in
    *[!0123456789]*)
        echo 'contains non-digit' ;;
    '')
        echo 'is empty' ;;
    *)
        echo 'contains only digits'
esac

In the bash shell, you can use the above code too, as it portable and would work in all sh-compatible shells, or you could use

#!/bin/bash

pattern='*[!0123456789]*'

if [[ $1 == $pattern ]]; then
   echo 'contains non-digit'
elif [ -z "$1" ]; then
   echo 'is empty'
else
   echo 'contains only digits'
fi
7
  • What is the purpose of enclosing the pattern with * at each end?
    – Veak
    Dec 23, 2021 at 20:04
  • @Veak *[!0123456789]* matches a non-digit anywhere in a string. [!0123456789] matches a string consisting of a single non-digit character. The * at the start and end of the pattern allows the non-digit character to exists anywhere in the string, if it exists at all.
    – they
    Dec 23, 2021 at 21:40
  • [[ doesn't need shopt -s extglob to use extglob
    – rowboat
    Dec 24, 2021 at 9:00
  • @rowboat Testing on bash 5.1.12 shows that the shell option needs to be set to be able to use extended globbing patterns like +(...), also within [[ ... ]].
    – they
    Dec 24, 2021 at 9:05
  • 2
    That extglob is in effect by default inside [[...]] is "new" since 4.1. You'd still need shopt -s extglob with the ancient bash found on macos. Dec 24, 2021 at 15:01
1

If glob pattern matching is not absolutely required, you can alternatively use regular expressions instead.

With Bash you can use the =~ regex operator:

dgt='^[[:digit:]]+$'
[[ "$1" =~ $dgt ]] && echo "SUCCESS" || echo "FAILURE"
9
  • Thanks for letting me know. Corrected.
    – Stephan
    Dec 23, 2021 at 19:44
  • Does the matching of more characters than just 0123456789 happen in Ubuntu?
    – Veak
    Dec 23, 2021 at 20:14
  • Is there a way to detect when [0-9] matches more characters?
    – Veak
    Dec 23, 2021 at 20:16
  • 1
    @Veak, Try perl -XC -e 'for ($i = 1; $i <= 0x10ffff; $i++) {$i=0xe000 if $i==0xd800; print chr$i}' | bash -c 'while IFS= read -rN1 c; do [[ $c =~ [0-9] ]] && printf %s "$c"; done in a UTF-8 locale for instance. On Ubuntu 20.04 and in a en_GB.UTF-8 locale, I find that it matches over a thousand different characters. [[:digit:]] can also match characters other than 0123456789 on some systems, though not current versions of Ubuntu AFAIK. Dec 23, 2021 at 20:29
  • In the case of =~, it's down to the system's regexp libraries. You'll get the same behaviour with zsh unless the rematchpcre option is enabled. For globs though, in the case of bash, it can get even worse Dec 23, 2021 at 20:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.