Shell脚本内执行find命令报错但直接运行正常如何解决
问题原因
- 命令字符串的语法解析问题
Shell 执行存储在普通字符串中的命令时,仅会按空格分割内容作为目标命令的参数,不会解析字符串内包含的管道符、重定向符、引号包裹等 Shell 专属语法。
你代码里把 | wc -l 写在 str0 字符串中,执行 `$str0` 时,Shell 会把 |、wc、-l 全部当做 find 命令的入参传递,因此 find 报错无法识别 | 参数。你直接复制打印的命令到终端执行时是正常的,因为终端会先解析整行命令的管道语法,再分别执行 find 和 wc。
- 字符串内的引号不生效问题
你在str0中给文件名加的单引号,执行时会被当做-name参数值的一部分,而非 Shell 的包裹符。比如文件名是test.jpg,find实际收到的参数是'test.jpg'(带单引号),匹配不到真实存在的无单引号的文件名,因此去掉| wc -l后依然没有输出,$res为空。
修复方案
修正后的代码如下:
IMG_DIR=/hdd/diskS/Foto DirScan() { # 变量加双引号避免文件名带空格出错 for f in "$1"/* do fname=${f##*/} if [ -d "$f" ] then DirScan "$f" else # 直接写命令捕获输出,不要存到字符串再执行 res=$(find "$IMG_DIR" -name "$fname" | wc -l) echo "res=$res" # 数字比较用 -gt,判断匹配数大于1时再删除,避免把原文件也删掉 if [ "$res" -gt 1 ] then echo "Remove $f" # rm "$f" fi fi done } DirScan "$1"
补充注意点
- 建议用
$()替代反引号捕获命令输出,可读性和嵌套支持更好 - 所有变量引用都加双引号,避免文件名包含空格、特殊字符时执行出错
- 原逻辑判断
[ $res ]只要res非空就会执行删除,会误删仅存1份的原文件,建议改为判断数量大于1再执行删除
内容的提问来源于stack exchange,提问作者Igor Shevchenko
相关产品推荐
相关产品推荐

