Makefile未终止字符串错误:兼容含空格目录的解决办法
解决Makefile中含空格目录的未终止字符串错误
我在使用下面的Makefile时,反复遇到/bin/sh: 1: Syntax error: Unterminated quoted string错误:
BASE=/mnt/c/Users/kilgore/scripts SCRIPTS=$(BASE)/scripts CSV=$(BASE)/csv DIR= QUOTED_DIR := $(patsubst %, "%", $(DIR)) REPORTS=./$(firstword $(subst ., ,$(subst /, ,$(QUOTED_DIR))))/reports SH_INV=$(SCRIPTS)/inventory.sh PY_INV=$(SCRIPTS)/filecheck.py CSV_NAME=$(shell echo "$(DIR)" | sed -r "s/[[:punct:][:space:]]//g") .PHONY: peek csv scan peek: find "$(DIR)"* -maxdepth 0 -type d -exec sh -c 'echo -n "{}: "; find "{}" -type f -print | wc -l' \; scan: bash $(SH_INV) "$(DIR)" dir: @echo "$(DIR)" @echo $(REPORTS) INVENTORY=$(CSV)/$(CSV_NAME)_inventory.csv REPORT=$(CSV_NAME)_inventory.xlsx $(INVENTORY): bash $(SH_INV) "$(DIR)" >$@ $(REPORT): $(INVENTORY) unoconv -d spreadsheet -f xlsx -i FilterOptions=9,34 -o "$(REPORTS)/$(REPORT)" $< report: $(REPORT) report2: python3 $(PY_INV) -f "$(REPORTS)/$(REPORT)"
移除引号能消除错误,但我需要处理带空格的目录。请问如何在支持含空格目录的同时解决该未终止字符串错误?
错误根源
- 变量定义的引号问题:
QUOTED_DIR使用了HTML转义的"而非Makefile原生双引号,且当DIR为空时会生成空引号,后续字符串替换时会把引号混入路径,导致shell解析时出现未终止字符串。 - 路径处理逻辑错误:
REPORTS变量对带引号的QUOTED_DIR做切割,会把引号当作路径的一部分,最终生成的路径包含引号,传递给shell后引发语法错误。 - 命令引号嵌套冲突:
peek目标中find -exec sh -c的引号嵌套逻辑有问题,直接使用{}会和外层引号冲突。
解决方案及修改后的Makefile
BASE=/mnt/c/Users/kilgore/scripts SCRIPTS=$(BASE)/scripts CSV=$(BASE)/csv # 默认空目录,使用时通过 make DIR="带空格的目录" 指定 DIR= # 直接基于DIR提取第一级目录名,处理空DIR的情况 REPORTS=$(if $(DIR),./$(firstword $(subst /, ,$(DIR)))/reports,) SH_INV=$(SCRIPTS)/inventory.sh PY_INV=$(SCRIPTS)/filecheck.py # 用printf传递DIR避免空格解析问题 CSV_NAME=$(shell printf '%s' "$(DIR)" | sed -r 's/[[:punct:][:space:]]//g') .PHONY: peek csv scan dir report report2 peek: # 用位置参数传递路径,避免引号嵌套冲突 find "$(DIR)"* -maxdepth 0 -type d -exec sh -c 'echo -n "$1: "; find "$1" -type f -print | wc -l' sh {} \; scan: bash "$(SH_INV)" "$(DIR)" dir: @echo "$(DIR)" @echo "$(REPORTS)" INVENTORY=$(CSV)/$(CSV_NAME)_inventory.csv REPORT=$(CSV_NAME)_inventory.xlsx $(INVENTORY): bash "$(SH_INV)" "$(DIR)" >$@ $(REPORT): $(INVENTORY) # 确保报告目录存在 mkdir -p "$(REPORTS)" unoconv -d spreadsheet -f xlsx -i FilterOptions=9,34 -o "$(REPORTS)/$(REPORT)" "$<" report: $(REPORT) report2: python3 "$(PY_INV)" -f "$(REPORTS)/$(REPORT)"
修改说明
变量优化:
- 移除冗余的
QUOTED_DIR,直接在需要引用路径的地方给DIR加双引号"$(DIR)"。 REPORTS用if函数处理空DIR场景,避免生成无效路径;直接基于原始DIR切割目录名,不会混入引号。CSV_NAME改用printf传递DIR,避免echo处理空格时的解析问题。
- 移除冗余的
命令修复:
peek目标的find -exec sh -c改用位置参数$1传递路径,彻底避免引号嵌套冲突。- 所有涉及路径的命令都给变量加上双引号,确保带空格的目录被shell正确解析。
- 添加
mkdir -p "$(REPORTS)"确保报告目录存在,避免unoconv执行失败。
内容的提问来源于stack exchange,提问作者Kilgore Trout
相关产品推荐
相关产品推荐

