While others have answered your specific question, I'll add that
if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then
Is a wrong way to check whether a string matches a regular expression for several reasons:
- You can't use
echo
for arbitrary data
- Leaving a parameter expansion unquoted like that
$1
above is the split+glob operator.
grep
doesn't match the regex against its full input, but on every line of it's input. So it would return true on foo\n-0\nbar
for instance.
- A regexp can match with zero length, so it's wrong in the general case to check if
grep
produces some output (note that command substitution strips trailing newline characters). It's better use grep -q
and rely on the exit status of grep
, rather than that of [
, and also avoid the command substitution.
- Note that that
grep
command can be simplified to grep -xE '-[0-9]+'
bash
, ksh93
and zsh
have a dedicated operator for (extended) regexp matching. To use it portably and reliably across all three (and bash-3.1), the syntax is:
re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
echo matches
fi
yash
and zsh
also support:
if [ "$1" '=~' '^-[0-9]+$' ]; then
echo matches
fi
The standard command to do string (basic) regex matching is expr
:
if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
echo matches
fi
Note that the ^
(but not $
) is implicit in expr
. We also use that leading space character to avoid problems with values of $1
that happen to be expr
operators.
Also note that if the regex contains \(...\)
, it will affect the behaviour of expr
.
All in all, it's better to use awk
instead which is another standard/portable way to do it (note that awk
uses extended regexps):
if STRING=$1 RE='^-[0-9]+$' awk '
BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...
Or use a function:
re_match() {
STRING=$1 RE=$2 awk '
BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}
if re_match "$1" '^-[0-9]+$'
In this case, you can also achieve it with a standard case
construct:
case $1 in
("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
(*) echo match;;
esac
To use grep
, you could use it with the --null
option (where supported as that's not a standard option) to tell it to work on NUL delimited records instead of newline delimited records. Since in most shells, $1
cannot contain NULs, that should be safe:
if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
echo match
fi