You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Shell脚本执行失败却返回成功退出状态?

问题描述

我写了一段Shell脚本,用来在网络设备目录下对所有文件执行whisper工具,转录文件存在同一卷里。但有时网络异常(比如卷断开)会导致转录保存失败,典型错误如下:

Traceback (most recent call last):
File "/Users/db/Library/Python/3.11/bin/whisper", line 8, in
sys.exit(cli())
^^^^^
File "/Users/db/Library/Python/3.11/lib/python/site-packages/whisper/transcribe.py", line 413, in cli
os.makedirs(output_dir, exist_ok=True)
File "", line 225, in makedirs
FileNotFoundError: [Errno 2] No such file or directory: '.'

脚本相关代码片段:

whisper "$file" --model large >> log
    if [[ $? -eq 0 ]]; then
        echo "exit success: $?"
        echo "*****success****** $?, `uname -n`, $me"  >> "${directory}/../${transdir}/${name}.txt"
    else
        echo "exit error: $?"
        echo "*****error****** $?, `uname -n`, $me"  >> "${directory}/../${transdir}/${name}.txt"       
    fi

正常执行成功会进入第一个if分支,但出现上述错误时,居然还是进入成功分支,仿佛whisper执行成功了一样。

补充说明:写入log文件没有问题。

更新1:测试错误参数的退出码

% whisper --bad_args; echo $?
whisper: error: the following arguments are required: audio
2

更新2:whisper的入口脚本内容

#!/opt/local/Library/Frameworks/Python.framework/Versions/3.11/bin/python3.11
# -*- coding: utf-8 -*-
import re
import sys
from whisper.transcribe import cli
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(cli())

问题原因与解决方案

核心原因

Python脚本抛出未捕获的异常时,默认会打印堆栈跟踪,但如果没有显式设置非零退出码,进程可能返回0(成功状态)。你遇到的FileNotFoundError属于运行时未捕获异常,whisper的cli()函数没有处理这个异常,导致Python解释器直接终止,但此时的退出码不一定是预期的非零值——在你的场景里,它返回了0,所以脚本误判为执行成功。

对比你测试的参数错误场景:whisper --bad_args返回码是2,因为这是argparse主动捕获的错误,argparse会显式调用sys.exit(code)设置非零退出码;但未捕获的运行时异常没有这个处理逻辑,退出码可能由系统决定,或者在某些环境下直接返回0。

解决方案

1. 基于输出内容判断执行结果

既然退出码不可靠,直接检查whisper的错误输出(堆栈跟踪打在stderr,需要先重定向到log):

# 把stderr也重定向到log,确保错误信息被记录
    whisper "$file" --model large >> log 2>&1
    # 检查log中是否包含错误关键词
    if grep -q "Traceback\|FileNotFoundError" log; then
        echo "exit error: 运行时异常"
        echo "*****error****** 异常, `uname -n`, $me"  >> "${directory}/../${transdir}/${name}.txt"
    elif [[ $? -eq 0 ]]; then
        echo "exit success: $?"
        echo "*****success****** $?, `uname -n`, $me"  >> "${directory}/../${transdir}/${name}.txt"
    else
        echo "exit error: $?"
        echo "*****error****** $?, `uname -n`, $me"  >> "${directory}/../${transdir}/${name}.txt"       
    fi

2. 修改whisper的cli函数,强制异常返回非零码

如果能修改whisper的transcribe.py文件,给cli()函数加一层异常捕获,确保任何未处理的异常都返回非零退出码:

# 在transcribe.py的cli函数外层添加try-except
def cli():
    try:
        # 原cli函数的所有代码逻辑
        ...
    except Exception as e:
        print(f"执行失败: {e}", file=sys.stderr)
        sys.exit(1)

这样所有未捕获的异常都会让进程返回1,Shell脚本里的$?就能正确识别错误。

3. 提前检查网络卷可用性

在执行whisper前,先检查目标目录是否可写,从源头避免后续出错:

# 检查转录目录是否存在且可写
    target_dir="${directory}/../${transdir}"
    if [[ ! -w "$target_dir" ]]; then
        echo "*****error****** 目录不可写, `uname -n`, $me"  >> "${target_dir}/${name}.txt"
        continue  # 跳过当前文件,处理下一个
    fi
    # 再执行whisper
    whisper "$file" --model large >> log 2>&1
    ...

内容的提问来源于stack exchange,提问作者d-b

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:20:29