【问题标题】:Bash in Make: how to expand dynamic variable names?Bash in Make:如何扩展动态变量名?
【发布时间】:2015-09-15 02:48:25
【问题描述】:

为了说明这个问题,我创建了一个 makefile,它首先定义了一个汽车列表,然后为每辆汽车定义了一个颜色列表:

CARS = Ford Ferrari Mercedes Toyota
Ford_COLOURS = black blue red white
Ferrari_COLOURS = red
Mercedes_COLOURS = black blue silver
Toyota_COLOURS = blue red white

然后,我想在我的一个 make 目标中循环遍历每辆车的所有颜色:

.PHONY: list
list:
    for car in ${CARS} ; do \
        car_colours=$${car}_COLOURS ; \
        echo $${car_colours} = "$${!car_colours}" ; \
        eval colours="$${!car_colours}" ; \
        for colour in $${colours} ; do \
            echo $${colour} ; \
        done ; \
    done

如您所见,我试图综合this question about generating dynamic variable names in bash 的想法和this question about how to evaluate (expand) dynamic names in bash 的一些答案。

不幸的是,我得到以下输出:

Ford_COLOURS = 
Ferrari_COLOURS = 
Mercedes_COLOURS = 
Toyota_COLOURS =

虽然我希望得到这样的东西:

Ford_COLOURS = black blue red white
black 
blue 
red 
white
Ferrari_COLOURS = red
red
Mercedes_COLOURS = black blue silver
black 
blue 
silver
Toyota_COLOURS = blue red white
blue 
red 
white

我该如何解决?

【问题讨论】:

    标签: bash makefile gnu-make


    【解决方案1】:

    按照my commentJonathan's answer 中的想法,我找到了一种方法,该方法涉及从执行内部for 循环的片段中启动另一个make 进程:

    .PHONY: list
    list:
        for car in ${CARS} ; do \
            car_colours_var=$${car}_COLOURS ; \
            ${MAKE} CAR_COLOURS_VAR=$${car_colours_var} single_car ; \
        done
    
    .PHONY: single_car
    single_car:
        for colour in ${${CAR_COLOURS_VAR}} ; do \
            echo $${colour} ; \
        done
    

    关键是中介CAR_COLOURS_VAR,它作为参数传递给子make进程,随后可以通过${${CAR_COLOURS_VAR}}语法由该进程扩展。

    【讨论】:

      【解决方案2】:

      问题是shell 不知道'make_COLOURS' 的列表。您可以使用:

      CARS = Ford Ferrari Mercedes Toyota
      Ford_COLOURS = black blue red white
      Ferrari_COLOURS = red
      Mercedes_COLOURS = black blue silver
      Toyota_COLOURS = blue red white
      
      .PHONY: list
      list:
              Ford_COLOURS="${Ford_COLOURS}"; \
              Ferrari_COLOURS="${Ferrari_COLOURS}"; \
              Mercedes_COLOURS="${Mercedes_COLOURS}"; \
              Toyota_COLOURS="${Toyota_COLOURS}"; \
              for car in ${CARS} ; do \
                  car_colours=$${car}_COLOURS ; \
                  echo $${car_colours} = "$${!car_colours}" ; \
                  colours="$${!car_colours}" ; \
                  for colour in $${colours} ; do \
                      echo $${colour} ; \
                  done ; \
              done
      

      请注意,原来eval colours="$${!car_colours}" 中的eval 丢失了eval。当它存在时,您会收到诸如/bin/sh: blue: command not found 之类的错误,因为eval 具有colours=black blue red white 并尝试在将环境变量colours 设置为black 的情况下执行blue

      【讨论】:

      • 感谢您的回答,不幸的是它几乎违背了CARS 列表的目的,因为它需要在循环中重复。我看到我的代码中的eval 可能是多余的,但是您所说的错误应该已经被$${!car_colours} 周围的引号所阻止,还是我遗漏了什么?
      • 你错过了什么; eval 有效地删除了引号。
      • 很抱歉你不能做你想做的事,但至少你知道为什么你得到了你所做的结果(我也得到了同样的结果)。有时候,生活是一头熊。您确定使用真正的 shell 脚本而不是配方中的片段不会更好吗?
      • 很高兴知道makefile中定义的变量的扩展在片段中不可用,这可能也意味着它们只扩展了一次;在执行片段之前。我喜欢 makefile 保持独立 - 也许我会创建另一个目标来执行单个 car 的内部循环,该目标由 list 目标传入,该目标调用 ${MAKE} 并带有一个选项。如果这是可能的话。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多