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

sff*_*ffc 5 whitespace makefile gnu-make

我知道类似这样的问题,但是我的问题专门关于makefile,尤其是gnumake。

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

示例文件:

OUTPUT=${shell cowsay hello}

all:
    @echo "$(OUTPUT)" > output.txt
Run Code Online (Sandbox Code Playgroud)

运行make之后,output.txt包含:

 _______  < hello >  -------          \   ^__^          \  (oo)\_______             (__)\       )\/\                 ||----w |                 ||     ||
Run Code Online (Sandbox Code Playgroud)

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

 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Run Code Online (Sandbox Code Playgroud)

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

Jos*_*sey 5

不幸的是,这是一个否定的答案。GNU Make 手册指出(强调是添加的):

shell函数执行的功能与大多数 shell 中的反引号执行的功能相同:它执行命令扩展。这意味着它接受 shell 命令作为参数并计算该命令的输出。make对结果的唯一处理是将每个换行符(或回车符/换行符对)转换为单个空格。如果有尾随(回车符和)换行符,它将被简单地删除。

我认为这没有eval帮助define

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

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

all:
    @echo "$(OUTPUT)" > output.txt
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Rei*_*eek 5

我想将该输出捕获到一个变量中,然后将该变量打印到一个文件中。

似乎没有办法绕过 的make机制将 shell 命令输出中的换行符转换为空格。与原始方法保持接近的一个技巧是,在将输出分配给变量时,让 shell 将换行符转换为一些不常见的字符(例如),然后在将该变量写入文件\1时将其转换回来。echo像这样的东西:

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

all:
        @echo "$(OUTPUT)" | tr '\1' '\n' > output.txt
Run Code Online (Sandbox Code Playgroud)

对我来说,这导致

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