首页 > 解决方案 > 将 Makefile/Bash 列表转换为 Python 列表

问题描述

使用以下 Makefile 文件:

datetime := $(shell date +%Y%m%d%H%M%S)
    
target := $(shell echo $$TARGET)

dothis:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns('1', '2', '3')); \
                "
        
dothat:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns('1', '2', '3')); \
                print('done')"

我可以

$ TARGET=folder1 make dothis

$ TARGET=folder2 make dothat

wheredothis执行一个 Pyhton 脚本并dothat执行另一个 Python 脚本,$target来自命令行并在 Python 脚本中被替换。

在这两种情况下,我都会传递一个列表ignore_patterns,因为列表是相同的,dothis并且dothat我想在 Makefile 上只定义一次,并将它作为变量传递到 Python 脚本中,就像我对datetime.

如何从 Bash/Makefile 列表转换为 Python 列表?

我尝试了以下方法,但它不起作用。

datetime := $(shell date +%Y%m%d%H%M%S)
    
target := $(shell echo $$TARGET)
                
list := $(1 2 3)

dothis:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(list))); \
                "
        
dothat:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(list))); \
                print('done')"

标签: pythonmakefile

解决方案


make没有列表,甚至没有数字。它只有字符串。但这应该足以满足您的目的。

然而,在我们开始之前,对您的示例代码有几条评论:

  • 如果您设置TARGET环境变量的唯一目的是能够将其值传递给 makefile 的target宏,那么您的灵感来自Rube Goldberg。您可以直接make在命令行中设置宏- 分配只需要作为参数出现:make

     make target=folder1 dothis
    

    或者

     make dothat target=folder2
    
  • 在 makefile 中,$()语法要求扩展宏或(仅限 GNU make)函数调用。 $(1 2 3)不表达其中任何一个,因为1 2 3它不是有效的变量名,1也不是任何内置函数的名称。您不需要在make宏值的文字周围使用特殊分隔符。

  • 您不需要或特别想要一个 Python 列表作为shutil.ignore_patterns(). 您所需要的只是一个逗号分隔的参数序列。如果您打算呈现 glob,那么您需要提供适当的 Python 引用,但您不需要为make.

  • 如果您有一个 make 规则,其配方实际上并未创建目标(作为文件),那么make通过将此类规则的目标指定为特殊目标的先决条件来提醒这一点通常是一个好主意.PHONY。那是一种 GNU 主义,但在make不理解它的 s 中它应该是无害的,而且无论如何你已经依赖于 GNU 特定的特性。

像这样的东西应该工作:

datetime := $(shell date +%Y%m%d%H%M%S)

# Default to the current working directory; can be overridden on the command line:
target := .

# The arguments to to shutil.ignore_patterns, which are text to `make`:
ignore := 1, 2, 3

dothis:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore)))"
        
dothat:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore))); \
                print('done')"

.PHONY: dothis dothat

但是,对于这种特殊情况,我会走得更远。您的两个 Python 脚本是相同的,只是它们是否包含该print('done')语句。为什么要重复这一切?有几种方法可以避免重复,但这是更简单的方法之一:

datetime := $(shell date +%Y%m%d%H%M%S)

# Default to the current working directory; can be overridden on the command line:
target := .

# The arguments to to shutil.ignore_patterns, which are text to `make`:
ignore := 1, 2, 3

dothis:
    @python -c "import shutil ; \
                from shutil import copytree, ignore_patterns; \
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore)))"

# First, build target dothis, then print "done":
dothat: dothis
    echo done

.PHONY: dothis dothat

推荐阅读