4

The following:

expr "/foo" : "/"

Results in a syntax error. I don't understand why?

These variations do not cause a syntax error:

expr "/foo" : "/*"
expr "/foo" : "/\/"
expr "foo" : "f"

At first I thought it might be an escaping issue, but forward slash doesn't seem to be documented as a special character for BRE's. And then I noticed that if either arg to expr string matching is a single forward slash, it causes the syntax error.

This also causes a syntax error:

expr "/" : "f"

(I'm running on a Mac - Darwin Kernel Version 24.6.0)

Kusalananda
355k41 gold badges732 silver badges1.1k bronze badges
asked Sep 1 at 16:58
New contributor
engber is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
9
  • 2
    This doesn't return me an error. Commented Sep 1 at 17:01
  • Hi engber, what shell are you running, in which version? Please add the output of running (exactly) $SHELL --version to your question! Thank you, and welcome here. Same for expr --version, please! Commented Sep 1 at 17:05
  • 1
    Does expr "//foo" : "/" work? This MacOS man page suggests "The // characters act to eliminate ambiguity with the division operator" Commented Sep 1 at 17:51
  • 1
    @steeldriver problem likely that that / argument is interpreted as a division operator which is missing operands, so you'd need expr x/foo : x/. I can reproduce on FreeBSD FWIW. Commented Sep 1 at 19:17
  • 2
    @MarcusMüller expr --version just output --version on macOS, just like it does on OpenBSD and with busybox. It is less likely to be helpful in any other way than to let you know it's not the GNU coreutils variant, which I think has already been established. Commented Sep 1 at 19:18

1 Answer 1

7

The forward slash isn't special in regular expression, nor is it special in the shell, so it doesn't need any quoting.

But these are also errors with the expr on Mac:

% expr : : .
expr: syntax error
% expr % : .
expr: syntax error

The man page also has this note on one example:

Since [the variable] might represent the path /, it is necessary to prevent it from being interpreted as the division operator. The // characters resolve this ambiguity.

So, it looks this version of expr identifies anything that looks like an operator as an operator regardless of the position within in the expression, and then you get the syntax error in the above cases since an expression can't start with a binary operator. Even if interpreting those as strings instead would form a valid expression.

You could prepend something like an x to both parts of the expression to prevent the strings from looking like operators, i.e. something like expr x/foo : x/ or expr x% : x. works... at the cost of looking rather silly.

The man page has another note:

The syntax of the expr command in general is historic and inconvenient. New applications are advised to use shell arithmetic rather than expr.

And even if this isn't arithmetic, that's a good suggestion.

Instead of expr, you can do regex matches directly in Bash1:

bash-3.2$ if [[ /foo =~ ^/ ]]; then echo match. ; fi
match.

or, if you just want to check if the string starts with a slash, a pattern match (like filename globs) would do:

bash-3.2$ if [[ /foo == /* ]]; then echo match. ; fi
match.

or, the same pattern match with a case statement which works in any POSIX shell:

$ case /foo in /*) echo match. ;; esac
match.

1 with the caveat that bash's =~ uses Extended Regular Expressions while expr uses Basic Regular Expressions, both having different feature sets: BREs support back reference (as in \(.\)1円 to match two identical characters) while EREs support alternation (as in (foo|bar)); some ERE implementations do support back references and some BRE implementations support alternation (using \|) as an extension over the standard though.

answered Sep 1 at 19:21

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.