Shell脚本执行报错:sh运行时出现Bad substitution错误
解决sh执行脚本时的Bad substitution错误
你遇到的问题根源很明确:你的脚本用了Bash专属的字符串替换语法 ${f// /_},但当你用sh test.sh执行时,sh在很多Linux系统里默认指向的是Dash(而非Bash),Dash并不支持这种参数展开语法,所以就抛出了Bad substitution错误。
下面给你两种可行的解决方案,适配你要配置到crontab的需求:
方案1:强制用Bash执行脚本(推荐)
其实crontab里完全可以指定用Bash来运行脚本,不需要局限于sh。你只需要做两件事:
- 保持你的原脚本不变(因为它本身是合法的Bash脚本):
#!/bin/bash for f in /home/admin1/abc/*.kmz do mv "$f" "${f// /_}" done - 在crontab里配置命令时,明确调用Bash路径(通常是
/bin/bash):# 示例:每天凌晨2点执行脚本 0 2 * * * /bin/bash /path/to/your/test.sh
这样既保留了Bash简洁的语法,又能在crontab里正常运行。
方案2:修改脚本为sh兼容写法
如果因为某些限制必须用sh执行,那就要把Bash专属的替换语法改成POSIX兼容的写法,比如用sed来处理文件名替换:
#!/bin/sh for f in /home/admin1/abc/*.kmz do # 用sed把所有空格替换成下划线 new_name=$(echo "$f" | sed 's/ /_/g') # 执行重命名,注意引号要保留,避免文件名含特殊字符出问题 mv "$f" "$new_name" done
或者用awk也能实现同样的效果:
new_name=$(echo "$f" | awk '{gsub(/ /,"_"); print}')
额外的crontab注意事项
在crontab里运行脚本时,还要注意两个常见坑:
- 路径问题:crontab的默认PATH比较窄,建议脚本里用绝对路径(比如
/bin/mv而不是mv),或者在脚本开头添加PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin来扩展环境变量。 - 测试先行:可以先手动用
sh test.sh运行修改后的脚本,确认重命名正常;或者在脚本里把mv改成echo mv,先打印出要执行的命令,验证替换逻辑没问题再实际执行。
内容的提问来源于stack exchange,提问作者Deepak




