从Bash错误处理SQLPlus - 无法正常工作

时间:2016-06-20 12:39:42

标签: oracle bash sh sqlplus ksh

我已阅读有关此问题的所有相关链接以及类似问题/答案,preveland回答是先设置whenever SQLERROR EXIT SQL.SQLCODE; 然后才进行查询,然后使用:ERRORCODE=$?

检查SQL Plus返回码

以下是一个示例脚本:

GetAmountOfChunks()
{
 export CHUNK_AMOUNT=`sqlplus -s $CONSTR<<SQL
    set heading off;
     set trim on;
     set feed off;
     whenever SQLERROR EXIT SQL.SQLCODE;
     select 1/0 from dual;
     --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
     /
SQL`

当运行调试模式时,它会给出:

++ sqlplus -s USER/PASS@HOST/DB
+ export 'CHUNK_AMOUNT=     select 1/0 from dual
                      *
ERROR at line 1:
ORA-01476: divisor is equal to zero'
+ CHUNK_AMOUNT='     select 1/0 from dual
                      *
ERROR at line 1:
ORA-01476: divisor is equal to zero'
+ ERRORCODE=0
+ '[' 0 -ne 0 ']'

如您所见,返回的代码为0! 我预计如果不是1476,那么至少196(最多8个字节),但不是0表示成功!

请帮忙......

感谢。

1 个答案:

答案 0 :(得分:2)

您的ERRORCODE被设置为零,因为您正在运行SQL * Plus的子shell中的退出代码是viq反引号。 SQL * Plus过程的退出代码是196,但是您没有捕获它,并且在heredoc中执行此操作并不容易。进程中的标准输出 - 您正在捕获的 - 不是退出代码,而是打印的查询和错误消息。即使您可以捕获它,我也不确定您如何区分出现错误的196或您的实际查询。

你可以做一些事情,比如在隐藏错误的块中运行查询并打印默认值或实际计算值,或者只查看输出的最后一行并尝试解释它;但是你仍然会反对它,显示正在运行的命令。 SQL * Plus有set echo off但是对交互式会话没有任何作用,这仍然是输入重定向。

另一种方法是创建一个脚本文件并临时存储输出:

echo "
    set pages 0
    set trim on
    set feed off
    set echo off
    whenever SQLERROR EXIT FAILURE
    select 1/0 from dual;
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
    exit 0;
" > /tmp/GetAmountOfChunks_$$.sql
sqlplus -s -l $CONSTR @/tmp/GetAmountOfChunks_$$.sql > /tmp/GetAmountOfChunks_$$.out
if [[ $? -eq 0 ]]; then
  export CHUNK_AMOUNT=`cat /tmp/GetAmountOfChunks_$$.out`
else
  # whatever you want to do on error; show output file? set default?
  cat /tmp/GetAmountOfChunks_$$.out
fi

rm -f /tmp/GetAmountOfChunks_$$.sql /tmp/GetAmountOfChunks_$$.out

这会创建一个(特定于进程的).sql文件;执行将输出(减去语句,通过set echo off)写入.out文件;检查SQL * Plus退出代码;如果为零,则从文件中获取结果。

当您暗示依赖SQL.SQLCODE检测shell脚本中的错误是危险的,因为您可能会收到包含为零的错误,因此我使用了通用FAILURE。如果您需要真正的错误代码,可以从输出文件中获取它。

使用PL / SQL块的另一种方法:

set -f
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL
    set heading off;
    set trim on;
    set feed off;
    whenever SQLERROR EXIT FAILURE;
    set serveroutput on;
    declare
      chunk_amount number;
    begin
      select 1/0 into chunk_amount from dual;
      --SELECT COUNT(*) INTO chunk_amount FROM CNV_CHUNKS_PROC_STATUS;
      dbms_output.put_line(chunk_amount);
    exception
      when others then
        dbms_output.put_line(sqlcode);
    end;
    /
    exit 0
SQL
exit $?`
ERRORCODE=$?

如果PL / SQL块运行,则ERRORCODE将为零,CHUNK_AMOUNT将成为计算值(如果成功),或SQL代码(如果它引发异常);因为那将是负面的(在你的例子中是-1476)你可以测试它是否预期,如果你只期望正值。

如果由于语法错误或凭据无效而无法运行该块(请注意我隐藏的-l标志),那么ERRORCODE将为1,CHUNK_AMOUNT将具有错误文本,例如ERROR: ORA-12154: TNS:could not resolve the connect identifier...或其他任何实际出错的地方。 set -f将错误消息中的*停止从当前目录扩展为文件列表。

或者更简单,更接近原作:

set -f
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL
    set heading off;
    set trim on;
    set feed off;
    whenever SQLERROR EXIT FAILURE;
    select 1/0 from dual;
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
    exit 0
SQL
exit $?`
ERRORCODE=$?

现在ERRORCODE成功为0且CHUNK_AMOUNT的任何错误ERRORCODE的计算值为1,您可以直接测试,实际错误始终为{{ 1}} - 但只是作为字符串,你不能以这种方式获得-1476。