在 Makefile 中迭代 bash 关联数组

bri*_*ian 6 bash make associative-array

$ bash -version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)

考虑以下 shell 脚本:

#!/bin/bash

declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )

for key in "${!PROVS[@]}" ; do \
  touch "foo_${key}_${PROVS[${key}]}" ; \
done
Run Code Online (Sandbox Code Playgroud)

我正在尝试在 Makefile 中执行等效操作:

SHELL := /bin/bash
.PHONY: foo
foo:
  declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )

  for key in "$${!PROVS[@]}" ; do \
    touch "foo_$${key}_$${PROVS[$${key}]}" ; \
  done
Run Code Online (Sandbox Code Playgroud)

真的不想touch文件;我这样做是因为我不能@echo——@ 不会被视为在行的开头,因为我处于循环中。或者这就是似乎正在发生的事情。

无论如何,关键是循环似乎根本没有运行,因此touch/echo业务。上面shell脚本的内容正是make终端回显的内容。我添加了 shebang 并将其作为健全性检查运行 - 就像一个魅力。

使用常规数组工作正常:

for prov in NL PE NS NB QC ON MB SK AB BC YK NT NU ; do \
Run Code Online (Sandbox Code Playgroud)

但是,我也需要这些代码(10、11 等)。

任何人都对此有所了解?

虽然我不需要它,但我也想知道如何(或者如果可能)在文件顶部分配 PROVS 变量,同时还使用“declare -A”。

编辑: 我以某种方式弄乱了 Makefile 示例,因此它只是一些内联 shell 命令,而不再是配方。我已经添加回“foo:”目标来澄清。

tri*_*eee 7

如果您的代码摘录具有适当的代表性,那么您似乎是直接在 Makefile 中键入 Bash 命令并期望 Make 使用 Bash 执行它们。这不是它的工作原理。Makefile 的语法完全不同。 配方中,您可以键入 Bash 命令;配方中的每一行都将在单独的子 shell 中执行。所以你至少需要两个改变:

  • 您的 shell 命令需要位于目标中。
  • declare需要在同一个外壳作为循环运行; 否则你declare在一个 Bash 实例中,然后退出,然后在一个单独的实例中运行循环,该实例对 now-lost 一无所知declare

这是使用这些更改对 Makefile 进行的简单重构。

SHELL=/bin/bash   # This is the standard compliant method

.PHONY: all
all:
    declare -A PROVS=( ["NL"]=10 ["PE"]=11 ["NS"]=12 ["NB"]=13 \
        ["QC"]=24 ["ON"]=35 ["MB"]=46 ["SK"]=47 ["AB"]=48 \
        ["BC"]=59 ["YK"]=60 ["NT"]=61 ["NU"]=62 )\
    ; for key in "$${!PROVS[@]}" ; do \
        touch "foo_$${key}_$${PROVS[$${key}]}" ; \
    done
Run Code Online (Sandbox Code Playgroud)

演示:http : //ideone.com/t94AOB

@静默运行命令的约定适用于整个命令行。因此,你可以把它放在declare上面,在这种情况下,它会在整个命令行提交给 Bash 之前被剥离。在其他任何地方,它都不会被剥离或理解,并且它显然会在被调用的 shell 中导致 Bash 语法错误。

@无论如何,对规则的痴迷是一种反模式。make -s如果您不想看到输出,请运行;关闭make只会使调试规则变得更加困难。)