Shell makefile 中的循环语法 if/else

Shell loop syntax inside makefile if/else

我已经循环了,我需要将其添加到 if else 语句中, 如果值 ==app1 打印 x 否则打印 y

我试过以下方法 但是当我添加 else 时出现语法错误,

我做错了什么?

runners:
    @for a in $(apps) ; do
       if (( a ==  "app1"));then
        echo first: $$v ;
       else
        echo second: $$v ;
        fi
     done

您对 sh if/else 使用了错误的语法。并且您必须在命令的每一端添加一个 \ 作为所有 运行 作为 make 启动的 shell 中的单个命令。注意:\ !

后没有空格

应该是这样的:

runners:
    @for a in $(apps) ; do \
        if [ $$a = "app1" ]; then\
        echo first: $$a ; \
        else \
        echo second: $$a ; \
        fi \
    done

顺便说一句:你真的要打印$v吗?我希望 $a 而不是 ;)

生成文件:

apps=app1 app2

runners:
    @for a in $(apps) ; do \
        if [ $$a = "app1" ]; then \
            echo "first: $$a" ; \
        else \
            echo "second: $$a" ; \
        fi \
    done

打印

first: app1
second: app2

1) 我更喜欢用bash作为我的shell,因为我已经习惯了。因此,我在 makefile 的顶部使用 SHELL:=/bin/bash。但是当系统不提供 /bin/bash..

时,您的整个 makefile 就会失败

2) 如果你想对食谱中的所有行使用相同的 shell,你可以使用特殊目标 .ONESHELL 这可以防止你在每个之后使用 ;\后面没有空格的行(容易出错)。但是如果你使用 .ONESHELL 那么你的 makefile 中的所有食谱都是如此(我使用它,但你可能不想要)。

3) 如果 runners 不是文件(看起来像,因为您没有在食谱中创建文件),我建议将其设为 .PHONY。当碰巧有一个名为 runners 的文件时,这会阻止 make 执行它。

4) 双括号((...))用于算术展开。它根本无法比较字符串。使用单括号或双括号。参见 this great post

5) 我还认为您想要打印 a,因此将 $$v 替换为 $$a

所以总的来说,只要你有 /bin/bash:

SHELL:=/bin/bash
.ONESHELL:
.PHONY: runners
apps:=app2 app3 app1 app5
runners:
    @for a in $(apps) ; do  <<-- ; between commands as usual
      if [[ "$$a" ==  "app1" ]]; then
        echo first: $$a  <<-- no need for ; because of .ONESHELL
      else
        echo second: $$a
      fi
    done

Output:

second: app2
second: app3
first: app1
second: app5

注意:上述解决方案仅适用于最近的 "make" 版本(可能 >4)。 OSX 例如包括 Gnu make 3.81。所以你需要使用 Homebrew

安装一个更新的 make
brew reinstall make --with-default-names