将命令输出保存到 Makefile 变量时如何保留空格?

How to preserve whitespace when saving command output to a Makefile variable?

我知道像 this one 这样的问题,但我的问题专门针对 makefile,特别是 gnumake。

我有一个命令可以打印换行符和其他空格以标准输出。我想将该输出捕获到一个变量中,然后将该变量打印到一个文件中。

示例生成文件:

OUTPUT=${shell cowsay hello}

all:
    @echo "$(OUTPUT)" > output.txt

运行make后,output.txt包含:

 _______  < hello >  -------          \   ^__^          \  (oo)\_______             (__)\       )\/\                 ||----w |                 ||     ||

我希望它保留空格而不是包含:

 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

我实际使用的命令不是 cowsay,但它输出类似的空格和换行符。

不幸的是,这是一个否定的答案。 GNU Make Manual states(强调已加):

The shell function performs the same function that backquotes perform in most shells: it does command expansion. This means that it takes as an argument a shell command and evaluates to the output of the command. The only processing make does on the result is to convert each newline (or carriage-return / newline pair) to a single space. If there is a trailing (carriage-return and) newline it will simply be removed.

我认为 evaldefine 没有帮助。

我能看到的唯一解决方法是将 cowsay hello 命令 存储在变量中,而不是命令的输出,如:

OUTPUT=$$(seq 5)     # seq 5 replaces cowsay hello

all:
    @echo "$(OUTPUT)" > output.txt

如果 cowsay hello 的计算成本很高,或者有副作用,则此变通方法很糟糕。第二种解决方法是保留其输出,但将换行符替换为任意字符,例如使用 sed,然后将换行符添加回去。例如:

OUTPUT=$(shell seq 5 | sed s/$$/xxx/)            # add xxx to the end of each line

all:
    @echo -n $(OUTPUT) ' ' | sed 's/xxx /\n/g'   # replace xxx-space with line break

I want to capture that output into a variable and then later print the variable to a file.

似乎没有办法解决 make 将 shell 命令输出中的换行符转换为空格的机制。在将输出分配给变量时,将 shell 转换为一些不常见的字符(如 </code>),然后让它将其翻译回来当 <code>echo-ing 将该变量写入文件时。像这样:

OUTPUT=$(shell cowsay hello | tr '\n' '')

all:
        @echo "$(OUTPUT)" | tr '' '\n' > output.txt

对我来说,这会导致

$ make
$ cat output.txt 
 _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

由于 $(shell) 去除了换行符,只需将它们替换为另一个字符或模式即可。返回 make 后,用换行符替换该字符。

这里我选择了:作为我的换行符。 YMMV

define \n


endef

cow := $(subst :,${\n},$(shell cowsay hello | tr \n :))

$(error [${cow}])

给予

$ make
Makefile:7: *** [ _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
].  Stop.

不过您会发现在食谱中使用 ${cow} 很棘手!

Base64编码

我建议你将 cowsay 的输出编码为 base64:

$ cowsay hello

 _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


$ cowsay hello | base64 -w0
IF9fX19fX18gCjwgaGVsbG8gPgogLS0tLS0tLSAKICAgICAgICBcICAgXl9fXgogICAgICAgICBcICAob28pXF9fX19fX18KICAgICAgICAgICAgKF9fKVwgICAgICAgKVwvXAogICAgICAgICAgICAgICAgfHwtLS0tdyB8CiAgICAgICAgICAgICAgICB8fCAgICAgfHwK

生成文件

cow:
    @echo IF9fX19fX18gCjwgaGV.... | base64 -d

make cow

现在只需 运行 make cow 即可正确显示(没有错误的换行符)

$ make cow

 _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||