为什么我的 find (+ sed) 命令在终端中有效,但在 makefile 中无效?

为什么我的 find (+ sed) 命令在终端中有效,但在 makefile 中无效?

我有以下命令:

find stdlib/main -type f -exec sh -c "echo {} | sed -e 's/stdlib\/main\///g' -e 's/\.q//g' -e 's/\//\./g' -e 's~^~/resource:\"{},~g' -e 's/$/\"/g'" \;

目标是查找stdlib/main(和子目录)中的所有文件并将其格式化为如下形式:{filename},{filename-with-stdlibmain-removed-and-extension-removed-and-slashes-changed-to-dots}

当我自己运行该命令时,该命令完美运行。但我试图在 makefile 中使用它:

STDLIB_RESOURCES=$(shell find stdlib/main -type f -exec sh -c "echo {} | sed -e 's/stdlib\/main\///g' -e 's/\.neo//g' -e 's/\//\./g' -e 's~^~/resource:\"{},~g' -e 's/$/\"/g'" \;)

当我运行 makefile 时,每个找到的文件都会出现以下错误之一:

sed: -e expression #5, char 5: unterminated `s' command

我在这里缺少什么?

答案1

您缺少的主要内容是要$制作一个特殊字符,并且 Make 和 shell 中的引用是不同的。

例如

's/$/\"/g'

`` 对将它们内部的所有内容保护到外壳(并且顺便做了\不必要的事情),但不做,所以使它看起来像

 's/\"/g' 

假设你没有一个名为的变量/(你可以在 make 中,但通常不在 shell 中)。

首先要做的就是替换$$$.

答案2

{}在您执行的内联脚本中使用find是一个代码注入漏洞。不要那样做。sh -c(脚本)的第一个参数应该用单引号引起来,并且该脚本的参数应该在其命令行上传递。

相反,请将find命令编写为如下所示(使用bash而不是sh能够${parameter//pattern/word}在一个地方使用):

find stdlib/main -type f -exec bash -c '
    for pathname do
        string=${pathname#stdlib/main/} # delete initial path
        string=${string%.*}             # delete suffix after last dot
        string=${string////.}           # change slashes to dots

        # output:
        printf "resource:\"%s,%s\"\n" "$pathname" "$string"
    done' bash {} +

这不是使用sed,而是使用参数替换来修改 找到的路径名find。内联bash脚本将对找到的文件批次执行,并将迭代每个批次中的路径名。printf将以与您的命令正在执行的方式相同的方式输出转换的数据(sed如果我设法正确地破译它,它不是只是你所描述的)。

稍后如何处理包含双引号和逗号的文件名是另一个问题(之后的输出字符串resource:可能难以解析)。

最简单的方法是将find命令放入单独的脚本中并从 GNU makein中调用它$(shell ...),否则您最终会得到类似的结果

STDLIB_RESOURCES := $(shell     \
find stdlib/main -type f -exec bash -c '    \
    for p do                                \
        s=$${p\#stdlib/main/};              \
        s=$${s%.*};                         \
        s=$${s////.};                       \
        printf "resource:\"%s,%s\"\n" "$$p" "$$s"; \
    done' bash {} + )

在你的 Makefile 中(由于 GNUmake处理变量等的方式)还要注意:=.您需要这个命令才能在分配给变量时立即执行,而不是每次访问变量时都执行。

有关的:

相关内容