没有重定向就能让`make`回显标准错误?

时间:2016-05-18 11:30:06

标签: bash makefile

我的Makefile运行程序中的一些目标,其输出(发送到stdout)我感兴趣。出于我不知道的原因,make的作者决定将执行的命令回显给stdout,后者会污染后者。

建议here提出了一个涉及交换文件描述符的问题。我想知道是否有更简单的方法强制make回显stderr

我查看了man的{​​{1}}页面,但除了make选项之外,没有找到任何结果。我更喜欢保留命令的回声,但是在-s

我也试过制作一个辅助目标(我做了所有其他目标的先决条件),我把它放在:

stderr

但是bash抱怨说3不是有效的文件描述符。我只试过exec 3>&2 exec 2>&1 exec 1>&3 ,但这没有任何影响...

4 个答案:

答案 0 :(得分:1)

make的原因显示stdout上的命令行是因为它是制作所需的POSIX标准,并且有30多年的历史预期。请参阅http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html并搜索" STDOUT"。

部分

您无法在配方中修改make程序中的文件描述符,因为配方是在子shell中运行的:您对文件描述符所做的任何更改仅在子shell中生效。在UNIX中,子进程无法修改其父进程的文件描述符。

同样,make中配方中的每个都在不同的子shell中运行。如果你想做一些奇特的事情,比如为食谱重定向输出,你必须把它全部写在一行:

exec 3>&2; exec 2>&1; exec 1>&3; <my command here>

当然,如果你打算这么做我会把它放在一个make变量中,而是使用那个变量。

没有办法让make将其输出写入stderr而不是stdout,除非你想修改GNU make的源代码并使用你自己构建的版本。只要您使用较新版本的GNU make(4.0及更高版本),就可以直接执行此操作,因为所有输出都是从一个plase(output.c)生成的。

答案 1 :(得分:1)

如果你不想污染make产生的回声输出,你不能简单地运行

make -n >&2 && make -s

这是示例Makefile:

all:
    ls
    echo done

以下是make的输出:

ls
Makefile
echo done
done

以下是make -n >&2 && make -s的输出:

ls
echo done
Makefile
done

当然,任何一步的输出都可以重定向到文件。

答案 2 :(得分:1)

你可以在Makefile中完全做到这一点:

define REDIR
@printf 1>&2 "%s\n" '$(1)'; $(1)
endef

.PHONY: all
all:
        $(call REDIR,echo updating .stamp)
        $(call REDIR,touch .stamp)

也就是说,控制命令通过宏回显自己。不幸的是,它涉及将您的食谱行编写为`$(call ...)语法。

REDIR现在实现了回显命令并通过宏扩展执行它的语义。

1>&2是特定于Bash的语法,用于将标准错误文件描述符复制到标准输出,因此该命令可以有效地打印到标准输出。

试运行:

$ make
echo updating .stamp
updating .stamp
touch .stamp

$ make 2> /dev/null
updating .stamp

正如您所看到的,updating .stamp,它是我们明确编码的echo行的输出,很好地转到标准输出。这些命令被隐式发送到标准错误。

答案 3 :(得分:0)

假设我们有以下Makefile

target-1:
    target-1-body
target-2:
    target-2-body
target-3:
    target-3-body

我们按如下方式更改:

target-1-raw:
    target-1-body
target-2-raw:
    target-2-body
target-3-raw:
    target-3-body

%-raw:
    echo "Error: Target $@ does not exist!"    
%:
    @make $@-raw 3>&2 2>&1 1>&3

调用与以前相同,例如make target-1

我们将另外两个目标make输出到stderr

仅供参考:trying进一步开发此解决方案,以便用户无法直接调用原始目标。