如何在Makefile目标中使用bash regex

如何在Makefile目标中使用bash regex,bash,makefile,gnu-make,Bash,Makefile,Gnu Make,在bash脚本中,以下正则表达式似乎运行良好: MY_STRING="FirstName-LastName-Gender-Age" MY_REGEX="([^-]+)-([^-]+)$" if [[ $MY_STRING =~ $MY_REGEX ]]; then echo "Match: $BASH_REMATCH" fi 我对在Makefile中使用这个脚本感兴趣。它似乎有语法问题。例如: my-target: MY_STRING="FirstName-LastName-G

在bash脚本中,以下正则表达式似乎运行良好:

MY_STRING="FirstName-LastName-Gender-Age"
MY_REGEX="([^-]+)-([^-]+)$"
if [[ $MY_STRING =~ $MY_REGEX ]]; then
    echo "Match: $BASH_REMATCH"
fi
我对在Makefile中使用这个脚本感兴趣。它似乎有语法问题。例如:

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

make中的正确语法是什么?上面的代码似乎在变量赋值、正则表达式中的“$”等方面存在问题。

这里有很多问题。第一个是make不调用bash作为它的shell,它调用
/bin/sh
(posixshell)。在许多系统上,它是到bash的链接,但在许多其他系统上,它是到dash或其他posixshell的链接。如果您尝试在makefile配方中使用这样的bash ISM,那么您的makefile是不可移植的。如果愿意,可以将
SHELL:=/bin/bash
添加到makefile中,以强制make始终使用bash。。。但如果bash不可用,它将在任何地方失败

第二个问题是make在单独的shell中调用配方的每个逻辑行。按照您编写的方式,每个变量赋值都是在一个新的shell中创建的,然后shell退出,并且该赋值将丢失。此外,只有if语句的第一行被发送到shell,这显然是一个语法错误。您需要在换行之前使用反斜杠,以确保整个脚本是一个逻辑行,并发送到同一个shell。。。这意味着您还需要在需要的地方添加分号以打断行

即使在shell脚本中,
MY_REGEX
的赋值也是可疑的,因为在双引号字符串中有一个未替换的美元符号。但是,它恰好对您有效,因为美元符号后面没有可以作为变量的字符。然而,为了安全起见,您应该在这里使用单引号字符串

最后,美元符号(
$
)是特殊的,因此如果要将
$
传递给shell,必须将其转义。Make使用两个美元符号
$$
来转义一个美元符号

因此,您的makefile应该如下所示:

SHELL := /bin/bash

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

就我个人而言,我会使用标准工具来重写此文件,而不是依赖bash等。但这是你的决定。

谢谢你。这些是非常有用的提示。在不指定bash的情况下如何实现这一点?使用默认的POSIX外壳是可移植的。这取决于你想做什么。您可能需要使用
sed
或类似工具来解析字符串。也许您想试试。它有一个函数
glob match
,它可以按照您的模式执行操作,但无需转到shell。但是没有实现Bash样式的regexp(在make中实现算法非常繁琐),但是glob匹配可能就足够了,即使它接受的字符串比regexp多。顺便说一句,我不会用连字符分隔名字——来自拉丁美洲的人经常使用双姓。