You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行Makefile时报/bin/sh: "(" unexpected语法错误的解决方法

问题诱因
  • Makefile 头部加#!/bin/bash没有任何作用:make执行规则内的命令时,不会解析文件头的shebang声明,默认固定调用/bin/sh作为命令执行环境,所有命令都交给sh解析运行。
  • 报错的直接原因:命令中使用的<(command)是进程替换语法,属于Bash、Zsh等Shell的扩展特性,不兼容POSIX标准的sh,sh解析到括号位置时就会抛出语法错误。
  • 额外隐藏问题:你写的目标文件编译规则本身存在逻辑错误,就算解决Shell问题也会编译失败:g++ $@ -o $<不仅把输入、输出参数写反,还缺少编译目标文件必需的-c参数,会错误地把.o文件当作源文件尝试链接成可执行文件,完全不符合预期。
  • 补充注意:GNU Make默认的wildcard函数不支持**递归通配符,你写的$(wildcard **/*.cpp)大概率无法匹配多层嵌套目录下的cpp源文件。
修复方案
  1. 指定make使用Bash执行命令,在Makefile最顶部添加内置变量配置,替换默认的sh:
    SHELL := /bin/bash
    
    该变量是make的内置配置项,优先级最高,设置后所有规则下的命令都会交给Bash执行,原生支持进程替换语法。
  2. 修正.o目标文件的编译规则,补全编译选项、调整参数顺序:
    %.o: %.cpp tests/%.cpp $(headers)
            g++ -c $< -o $@
    
    其中-c参数告诉g只编译生成目标文件、不执行链接操作;$<代表规则的第一个依赖项(待编译的cpp源文件),$@代表当前规则要生成的目标.o文件,参数顺序符合g的调用要求。
  3. (可选优化)如果需要可靠递归查找全目录下的cpp文件,把source变量的定义改为find命令实现,避免通配符不生效导致源文件遗漏:
    source := $(shell find . -name "*.cpp")
    

修复完成后的完整可运行Makefile参考:

SHELL := /bin/bash
source := $(shell find . -name "*.cpp")
headers := $(wildcard include/*.h)
objects := ${source:.cpp=.o}

run: $(objects)
        g++ -o run $(objects)
        diff -u <(cat $(source)) <(clang-format $(source))

%.o: %.cpp tests/%.cpp $(headers)
        g++ -c $< -o $@

如果不想依赖Bash特性提升跨环境兼容性,也可以把diff行的进程替换写法改为POSIX sh兼容的临时文件实现,不需要切换Shell也能运行:

run: $(objects)
        g++ -o run $(objects)
        clang-format $(source) > .format_tmp
        diff -u $(source) .format_tmp
        rm -f .format_tmp

内容的提问来源于stack exchange,提问作者Potatmen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:54:37