Makefile中sha256sum执行后无限挂起,CPU占用率0%问题求助
我有一个用于备份的Makefile,备份目录命名格式为2023-09-11,目录内包含3个磁盘镜像文件及对应的sha256校验文件:
# ls -1 2023-09-11/ home.img home.img.sha256 root.img root.img.sha256 var.img var.img.sha256
操作流程是先从U盘同步备份目录,再校验校验和是否正确,Makefile内容如下:
all: rsync shasum rsync: @rsync -rt --delete /mnt/udisk/LAPTOP/ . shasum: home root var home: @cd 20??-??-??/ && sha256sum -c home.img.sha256 root: @cd 20??-??-??/ && sha256sum -c root.img.sha256 var: @cd 20??-??-??/ && sha256sum -c var.img.sha256
执行时,rsync目标成功完成,文件已同步,但shasum目标出现异常:第一个校验目标home执行成功并输出OK后,进程无限挂起,无任何响应。通过ps命令可见第二个目标对应的sha256sum -c root.img.sha256进程存在,但CPU占用率为0%:
0.0 0.0 /usr/bin/make 0.0 0.0 /bin/sh -c cd 20??-??-??/ && sha256sum -c root.img.sha256 0.0 0.0 sha256sum -c root.img.sha256
请问我的Makefile存在什么问题?
通配符匹配多目录引发命令阻塞
规则中使用cd 20??-??-??/的通配符,若当前目录下存在多个符合日期格式的备份目录(比如未清理的旧备份),shell会将通配符展开为所有匹配目录名,导致cd命令因参数过多执行失败。此时sha256sum会在当前目录执行,若找不到对应的校验文件,sha256sum -c会默认等待从标准输入读取校验信息,从而造成进程挂起(CPU占用为0,等待用户输入)。即使只有一个匹配目录,这种写法也存在不确定性,若目录命名格式变化会直接失效。未声明伪目标导致规则可能被跳过
home/root/var未被标记为伪目标(.PHONY),如果当前目录下存在同名文件或目录,Makefile会判定目标已完成,直接跳过对应的校验步骤,引发非预期行为。
方案1:明确指定备份目录+声明伪目标
通过变量获取最新的备份目录,避免通配符的不确定性,同时声明伪目标确保规则每次都会执行:
# 获取最新的备份目录(按修改时间倒序取第一个) BACKUP_DIR := $(shell ls -td 20??-??-??/ 2>/dev/null | head -n 1) all: rsync shasum rsync: @rsync -rt --delete /mnt/udisk/LAPTOP/ . # 同步后校验目录是否存在,避免后续命令报错 @test -d "$(BACKUP_DIR)" || (echo "Error: Backup directory not found!" && exit 1) shasum: home root var # 声明伪目标,确保每次都执行校验规则 .PHONY: home root var home: @cd "$(BACKUP_DIR)" && sha256sum -c home.img.sha256 root: @cd "$(BACKUP_DIR)" && sha256sum -c root.img.sha256 var: @cd "$(BACKUP_DIR)" && sha256sum -c var.img.sha256
方案2:合并校验规则(简化版)
将三个校验命令合并为一个规则,减少子shell创建,提升效率:
BACKUP_DIR := $(shell ls -td 20??-??-??/ 2>/dev/null | head -n 1) all: rsync shasum rsync: @rsync -rt --delete /mnt/udisk/LAPTOP/ . @test -d "$(BACKUP_DIR)" || (echo "Error: Backup directory not found!" && exit 1) # 合并校验命令,避免重复切换目录 .PHONY: shasum shasum: @cd "$(BACKUP_DIR)" && sha256sum -c home.img.sha256 root.img.sha256 var.img.sha256
内容的提问来源于stack exchange,提问作者Martin Vegter

