3
votes

In a bash script, the following regex appears to work well:

MY_STRING="FirstName-LastName-Gender-Age"
MY_REGEX="([^-]+)-([^-]+)$"
if [[ $MY_STRING =~ $MY_REGEX ]]; then
    echo "Match: $BASH_REMATCH"
fi

I'm interested in using this script inside the Makefile. It appears to have syntax issues. For example:

my-target:
    MY_STRING="FirstName-LastName-Gender-Age"
    MY_REGEX="([^-]+)-([^-]+)$"
    if [[ $MY_STRING =~ $MY_REGEX ]]; then
        echo "Match: $BASH_REMATCH"
    fi

What would be the correct syntax for this in make? The above appears to have issues with variable assignment, issues with the "$" in the regex, etc.

1

1 Answers

3
votes

You have many problems here. The first one is that make doesn't invoke bash as its shell, it invokes /bin/sh (POSIX shell). On many systems that is a link to bash, but on many other systems it's a link to dash or some other POSIX shell. If you try to use bash-isms like this in your makefile recipes your makefile is not portable. You can, if you like, add SHELL := /bin/bash to your makefile to force make to use bash always... but it will fail anywhere that bash isn't available.

The second problem is that make invokes each logical line of your recipe in a separate shell. The way you have this written, every variable assignment is created in a new shell, then the shell exits and that assignment is lost. Further, only the first line of the if-statement is sent to a shell which is clearly a syntax error. You need to use backslashes before your newline to ensure the entire script is one logical line and is sent to the same shell... and that means you need to add semicolons to break lines where needed, as well.

Even in a shell script, the assignment of MY_REGEX is suspect because you have an unescaped dollar sign in a double-quoted string. However it happens to work for you because there's no character after the dollar sign that could be a variable. Nevertheless you should be using single-quoted strings here to be safe.

And finally, dollar signs ($) are special to make, so if you want to pass a $ to the shell you have to escape it. Make uses two dollar signs $$ to escape a single dollar sign.

So, your makefile should look like this:

SHELL := /bin/bash

my-target:
        MY_STRING="FirstName-LastName-Gender-Age"; \
        MY_REGEX='([^-]+)-([^-]+)$$'; \
        if [[ $$MY_STRING =~ $$MY_REGEX ]]; then \
            echo "Match: $$BASH_REMATCH"; \
        fi

Personally I would rewrite this to use standard tools rather than relying on bash etc. but that's your call.