I am trying to match using a glob pattern. However, this match is failing:
dgt='^+([0123456789])$'
[[ "$1" == $dgt ]] && echo "SUCCESS" || echo "FAILURE"
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityYour 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
*[!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.
bash
5.1.12 shows that the shell option needs to be set to be able to use extended globbing patterns like +(...)
, also within [[ ... ]]
.
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
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"
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
=~
, 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
12
,345
,23456
.dgt
is not matching if$1=23
.