zsh中移动通配匹配文件前如何正确检测其存在性?脚本问题求助
问题与解决方案
问题背景
拍摄照片采用NEF(RAW格式),通过RawTherapee转成JPG后,JPG的生成日期与原NEF文件不一致。为了和手机拍摄的照片混合制作幻灯片时排序正确,所有文件都采用YYYYMMDD-HH-MM-SS_前缀命名。需要将JPG文件名的日期前缀替换为对应NEF文件的日期前缀,但原脚本在NEF文件被删除/移动时会报错,甚至出现JPG被重命名为.JPG导致文件丢失的情况,.pp3文件也存在同样问题。
原脚本尝试用[[ -n *${nummer}.NEF(NY1) ]]判断文件存在,但逻辑有误,且[[ -f ]]未生效。
问题分析
- 原判断逻辑
[[ -n *${nummer}.NEF(NY1) ]]写法错误:zsh的glob限定符需要正确结合(#q)使用,直接在[[ -n ]]中写glob会导致匹配异常 - 当无匹配NEF时,
p_date=(*${nummer}.NEF(NY1))会赋值为空字符串,后续n_date=${p_date%.*}也为空,最终生成.JPG的错误文件名 [[ -f ]]未生效是因为原代码中未正确展开glob路径,直接使用模式字符串而非实际文件路径
修正后的脚本
#!/zsh # 将NEF文件的日期前缀同步到对应JPG和.pp3文件 # NEF示例:20241117-08-15-33_OZ8_3367.NEF # JPG示例:20241117-16-18-03_OZ8_3367.JPG # 处理JPG文件 for j_f in *.JPG; do # 提取文件名(不含扩展名) j_g=${j_f%.*} # 提取唯一标识部分(去掉日期前缀) nummer=${j_g#*_} # 匹配对应的NEF文件,存到数组中 local nefs=(*"${nummer}".NEF(N)) # 判断是否存在匹配的NEF文件 if (( ${#nefs[@]} > 0 )); then # 取第一个匹配的NEF文件(避免多文件冲突) local nef_file=${nefs[1]} # 提取NEF的日期前缀部分(不含扩展名) local nef_prefix=${nef_file%.*} # 目标JPG文件名 local target_jpg="${nef_prefix}.JPG" # 检查目标文件是否已存在,避免覆盖 if [[ ! -f "$target_jpg" ]]; then echo "重命名: $j_f -> $target_jpg" mv -- "$j_f" "$target_jpg" fi else echo "未找到对应NEF文件: $nummer.NEF,跳过JPG: $j_f" fi done # 处理.pp3文件 for pp3_f in *.pp3; do # 提取文件名(不含扩展名) p_g=${pp3_f%.*} # 提取唯一标识部分 nummer=${p_g#*_} # 匹配对应的NEF文件 local nefs=(*"${nummer}".NEF(N)) if (( ${#nefs[@]} > 0 )); then local nef_file=${nefs[1]} local nef_prefix=${nef_file%.*} local target_pp3="${nef_prefix}.pp3" if [[ ! -f "$target_pp3" ]]; then echo "重命名: $pp3_f -> $target_pp3" mv -- "$pp3_f" "$target_pp3" fi else echo "未找到对应NEF文件: $nummer.NEF,跳过PP3: $pp3_f" fi done
关键改进点
- 安全的文件存在判断:用数组存储匹配的NEF文件,通过数组长度判断是否存在,避免glob匹配失败导致的空值
- 避免空值错误:所有变量赋值前先确认匹配结果,杜绝空字符串导致的
.JPG错误命名 - 防止覆盖:增加目标文件存在性检查,避免误删已有文件
- 鲁棒的字符串处理:用
local限定变量作用域,避免全局变量污染;用--确保mv命令处理特殊文件名 - 清晰的错误提示:无匹配NEF时输出提示,便于排查问题
内容的提问来源于stack exchange,提问作者o.wo
相关产品推荐
相关产品推荐

