【问题标题】:Catching the exception thrown by python script in shell script在shell脚本中捕获python脚本抛出的异常
【发布时间】:2014-06-13 14:37:29
【问题描述】:

我有一个 shell 脚本,它打开一个文件并将它传递给 python 脚本来处理它。因此,如果文件有任何问题(例如,文件内容不是成功执行 python 脚本所需的格式),python 脚本会引发异常。因为我的目标是使用 python 脚本处理 N 个文件。我需要知道哪个文件导致脚本中断。我阅读了如何捕获命令执行引发的异常。 http://linuxcommand.org/wss0150.php 。但在我的情况下,它是引发异常的python脚本,我需要在shell脚本中知道引发了什么异常。任何人都可以帮助我如何进行此操作?

下面是sn-p的代码:

#!/bin/bash
yesterday=$(date --date "yesterday" "+%y%m%d")
ftoday=$(date --date "today" "+%m-%d-%Y")
year=$(date "+%Y")
fileList=$(find C:/logdata/$year/$ftoday/ -iname "*"$yesterday".log")
for var in $fileList
do
echo -e "\n START Processing File : $var" >> shelltestlog.txt
cat $var| ./scriptA.py 
echo -e "\n END Processing File : $var" >> shelltestlog.txt
done

【问题讨论】:

  • 如果您只想在脚本发现异常时停止脚本并立即进行调试。然后你可以使用语法:./scriptA.py || exit 1

标签: python bash shell


【解决方案1】:

如果您的 python 脚本在遇到异常时返回非零错误级别,您可以使用|| { } 记录消息:

./scriptA.py < "$file" || {
    printf "\n Python script scriptA.py failed with file \"%s\".\n" "$file" >> shelltestlog.txt
} 

我实际上是先简化你的代码:

#!/bin/bash

yesterday=$(date --date "yesterday" "+%y%m%d")
ftoday=$(date --date "today" "+%m-%d-%Y")
year=$(date "+%Y")

readarray -t filesList < <(find C:/logdata/$year/$ftoday/ -iname "*"$yesterday".log")

for file in "${filesList[@]}"; do
    printf "\n START Processing File : %s\n" "$file" >> shelltestlog.txt
    ./scriptA.py < "$file" || {
        printf "\n Python script scriptA.py failed with file \"%s\".\n" "$file" >> shelltestlog.txt
    }
    printf "\n END Processing File : %s\n" "$file" >> shelltestlog.txt
done

【讨论】:

  • 谢谢。使用上述方法,我解决了获取有关失败文件的信息的问题。但我无法捕捉到 .py 脚本引发的异常。
  • @Codelearner 异常不会跨进程边界传播。这是你能做的最好的事情,而不是像我建议的那样将整个事情重写为一个 Python 脚本。
  • @Zack,我同意你的看法。也许 Chepner 建议的方法有助于了解异常详细信息...
【解决方案2】:

您应该用 Python 重写 shell 脚本并将其合并到现有的 Python 脚本中。 您当前使用date 命令执行的操作可以使用datetimetime 模块完成。你用find 做的事情可以用os.walkfnmatch.fnmatch 做。

这是一个大纲:

#! /usr/bin/python

def scriptA(file_to_process):
    # the code currently in scriptA goes here;
    # modify it to read from `file_to_process` rather than `sys.stdin`

def get_file_list():
    # your bash logic to construct the file list goes here,
    # converted to Python as suggested above

def main():
   for filename in get_file_list():
       sys.stderr.write("Processing {}...\n".format(filename))
       try:
           scriptA(open(filename, "rt"))

       except SomeExceptionType as e:
           # handle exception...

       except SomeOtherExceptionType as e:
           # handle other kind of exception...

       sys.stderr.write("Done processing {}.\n".format(filename))

main()

【讨论】:

  • 感谢您提出另一种方法。
【解决方案3】:

未捕获的异常将产生打印到标准错误的回溯。你能做的最好的就是捕捉它,并尝试解析它。

if ! ./scriptA.py < "$var" 2> stderr.txt; then
  # Parse stderr.txt to see what exception was raised.
fi

【讨论】:

    【解决方案4】:

    你可以玩一些重定向游戏:

    # open file descriptor 3, pointing to the same destination as stdout
    exec 3>&1
    
    # run the script, 
    # python's stderr goes to stdout so it can be captured in a variable
    # python's stdout goes to file descriptor 3, displayed on the terminal
    python_stderr=$( ./scriptA.py < "$var" 2>&1 1>&3 )
    
    # close the file descriptor
    exec 3>&-
    

    然后你可以检查 $python_stderr 的模式

    case $python_stderr in
        "") echo "nothing on stderr" ;;
        *foo*) handle_foo_error ;;
        *bar*) handle_bar_error ;;
        *baz*) handle_baz_error ;;
    esac
    

    【讨论】:

    • 按照从左到右的顺序进行重定向很重要。
    猜你喜欢
    • 2022-10-20
    • 1970-01-01
    • 2014-10-21
    • 2015-02-10
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 2017-10-07
    相关资源
    最近更新 更多