【问题标题】:How should I embed a python script in a Makefile?我应该如何在 Makefile 中嵌入 python 脚本?
【发布时间】:2021-11-12 12:04:56
【问题描述】:

我想在Makefile 中嵌入一个python 脚本

我构建了一个 python -c 脚本(如下),它在我的 MacBook Hyper terminal 中运行良好:

% python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'

由于我还不知道的原因,如果我用它构建一个 Makefile,这似乎会失败(注意:一个制表符是四个空格...我在 Makefile 中使用了制表符缩进)。

all:
    $(shell python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))')

运行make all 目标...

% make all
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `python -c from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))''
make: `all' is up to date.
%

我已经为此苦苦挣扎了一段时间......

有人可以帮助解释为什么make all 失败以及修复此python -c 命令的最佳方法吗?我的 shell CLI python -c ... 命令在我的 MacBook 上成功启动了 Docker 桌面。

我知道有非 python 方法可以解决这个特定问题...我需要一个通用的 python Makefile 解决方案。

【问题讨论】:

  • 您可以将该脚本提取到 Python 文件中,然后运行它吗?这样可以解决各种逃逸问题,而且似乎更易于维护。
  • 我考虑在Makefile 中调用一个单独的.py 脚本,但我想要Makefile 中的所有变量和控制本机。我同意 oneliners 维护起来并不有趣......
  • 在食谱中使用 $(shell ...) 是一个常见的初学者错误,我们有一个规范的重复项:stackoverflow.com/questions/10024279/…

标签: python docker unix makefile subprocess


【解决方案1】:

由于 Python 的缩进要求,在 Makefile 中使用 python -c 很棘手。一个简单的解决方案是使用SHELL=/bin/bash,如果您想使用 Bash“C 风格”字符串:

SHELL=/bin/bash
all:
    # python command must be wrapped in single quotes _and_ have double dollar sign in front
    python -c $$'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'

(注意美元符号需要加倍才能对其进行转义。显然,这限制了 Makefile 对 Bash 可用系统的可移植性。$'...' 语法允许您使用转义码,如 \n\t 在一个字符串中,并将它们分别扩展为换行符和制表符。这个结构特别需要一个前导美元符号和字符串周围的单引号 - 只是'...' 略有不同,而$"..." 做了一些完全不同。)

你也可以define 一个make 多行变量。但在这种孤立的情况下,Python 无论如何都没有发挥任何有用的作用。

all:
    open --background -a Docker

如果open 失败,make 将终止并显示错误消息;从 Python 打印本质上相同的消息似乎是多余的。如果你想不顾错误继续,你可以这样做

all:
    open --background -a Docker || \
    echo "Docker desktop failed to launch: exit-code: $$?"

...虽然我认为未能从 Python 脚本中失败(原文如此)只是一个错误。

【讨论】:

  • 你在反斜杠之前有一个杂散的换行符,它不应该在那里仅供参考。
  • 我同意这个例子不需要python,但是......我们都访问过复杂的shell正则表达式......python -c $'import re'PCRE比处理更容易外壳正则表达式
  • Perl 大体上具有相同的正则表达式功能,并且对于单行者来说更容易一些,尽管在 Perl 中必须将所有美元符号翻倍也很乏味。
【解决方案2】:

我找到了一种在Makefile...中嵌入多行python脚本的相当简单的方法...

  1. 另存为Makefile...
define MULTILINE_PYTHON_SCRIPT
###########################################
# Start multiline python string here...
###########################################
from subprocess import getstatusoutput as gso

print("Here we go:")
for hello_int in [1, 2, 3,]:
    print('    Hello World %i' % hello_int)

retval, _ = gso("ls -la")
assert retval==0, "ls command execution failed"

###########################################
# End of multiline python string...
###########################################
endef
export MULTILINE_PYTHON_SCRIPT
EMBEDDED_PY := python -c "$$MULTILINE_PYTHON_SCRIPT"

.PHONY: nothing
nothing:
    echo "raw makefile command"

.PHONY: test
test:
    $(EMBEDDED_PY)

.PHONY: all
all:
    open --background -a Docker
  1. 测试输出:
% make nothing
echo "raw makefile command"
raw makefile command
%
% make test
python -c "$MULTILINE_PYTHON_SCRIPT"
Here we go:
    Hello World 1
    Hello World 2
    Hello World 3
%
%

【讨论】:

    猜你喜欢
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    相关资源
    最近更新 更多