GNU Makefile 中的进程替换

Joh*_*nes 13 shell bash make process-substitution

在 bash 提示符下,可以使用伪文件执行 diff:

diff <(echo test) <(echo test)
Run Code Online (Sandbox Code Playgroud)

将其按原样添加到 Makefile 失败:

all:
        diff <(echo test) <(echo test)
Run Code Online (Sandbox Code Playgroud)

错误(提示:/bin/sh 指向此系统上的 /bin/bash):

/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `diff <(echo test) <(echo test)'
Run Code Online (Sandbox Code Playgroud)

这是什么意思,有没有办法在不使用临时文件的情况下仍然区分两个输出?

Kus*_*nda 23

/bin/sh可能bash在您的系统上,但是当作为 调用时shbash将以 POSIX 模式运行(就像POSIXLY_CORRECT已定义或以 开头--posix)。

在这种模式下,不存在进程替换。

解决方案:

  1. 使用显式临时文件:

    all:
        command1 >tmpfile
        command2 | diff tmpfile -
        rm -f tmpfile
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用bash -c内嵌脚本:

    all:
        bash -c 'diff <(command1) <(command2)'
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将 Makefile 变量定义SHELL/bin/bash(或系统上的任何路径bash):

    SHELL=/bin/bash
    
    Run Code Online (Sandbox Code Playgroud)

如果您想要便携性,请使用第一个解决方案。如果您可以依赖于bash,请选择第二个。如果您另外不需要关心非 GNUmake实现,请使用第三个。


关于设置SHELL:POSIX 标准规定,Makefile 中的可执行文件应通过system()C 库函数调用make。此函数不保证使用SHELL环境变量(事实上,标准不鼓励这样做)。该标准还详细说明设置 Makefile 变量SHELL不应影响环境变量 SHELLmake然而,在我所知道的大多数实现中,Makefile 变量SHELL将用于执行命令。

实用程序的基本原理中make的建议是使用bash -c

省略MAKESHELL了其他make实现提供的历史特性和相关特性。在某些实现中,它用于让用户覆盖用于运行make命令的 shell 。这令人困惑;对于可移植的make,shell 应该由 makefile 编写者选择。此外,makefile 编写器不能要求使用备用 shell 并且仍然认为 makefile 可移植。虽然可以标准化指定备用 shell 的机制,但现有实现不同意这种机制,并且 makefile 编写者已经可以通过在目标规则中指定 shell 名称来调用备用 shell;例如:

python -c "foo"

  • 使用 SHELL 变量不符合 POSIX 的信息非常有帮助。也许使用`bash -c` 仍然更好。 (2认同)