bash - 使用 sqlplus 轮询并将结果记录到文件强制换行

标签 bash centos sqlplus

我正在尝试制作一个我认为是简单的 bash 脚本,它定期轮询远程数据库并将以下元素记录到日志文件中,其中只有最后两个元素是来自 sql 的行元素-查询:

Readable timestamp, timestamp, string, Request Duration

示例结果应如下所示:

Mon Sep 5 13:28:30 CEST 2016,1473074940127,text content, 4
Mon Sep 5 13:28:40 CEST 2016,1473074940127,text content, 3
Mon Sep 5 13:28:50 CEST 2016,1473074940127,text content, 2

此脚本的目的是主动监控和记录从我们的本地环境到远程数据库的响应时间,以便我们可以在测试时对应本地应用程序中的错误,以及最终的数据库连接问题或类似问题。出于这个原因,我们希望脚本也输出任何最终的错误消息。这些格式并不重要,但我们希望看到标准输出是“舒适的”单行。

我为此编写了以下非常简单的脚本,但它有一些怪癖,无论我如何调整它似乎都无法消除:

sleep_duration=10
while true; do

SECONDS=0
timestamp="$(date),"
echo -n $timestamp >> $LOG_PATH


sqlplus -s $database << EOF >> $LOG_PATH
    whenever sqlerror exit sql.sqlcode

    set echo off
    set heading off
    set linesize 1000
    set pagesize 0
    set numformat 9999999999999
    set colsep ,
    set null null

    SELECT COLUMN1, COLUMN2 FROM TABLE1;
    exit;
EOF

echo ', '$SECONDS >> $LOG_PATH

sleep $sleep_duration
done

我们向数据库发送的查询总是恰好返回包含两个元素的一行,并且这两个元素(INTEGER、VARCHAR2)总是具有相同的固定宽度。如果我们的应用程序在本地出现问题,它们都可以为 null。

我知道 SPOOL 和 TIMING 命令的存在,但已经测试并选择不使用这两个命令。假脱机查询不会向日志文件输出任何最终的意外错误,至少不会在错误终端输出的情况下进行欺骗,所以我首先使用了管道解决方案。看起来更简单。在数据库停机的情况下,TIMING 似乎无法正确显示查询的运行时间,因此我采用了 SECONDS 方法。我知道这对于包含的所有 sqlplus 开销来说并不那么精确,但无论如何我们对精确的指标不感兴趣,我们通常只对查看该过程是否需要不到一秒或几分钟感兴趣。毫秒基本上是无关紧要的。

然而,这有一个大问题,因为日志最终看起来像这样:

Mon Sep 5 14:50:47 CEST 2016, 1473079873483,text output

, 0
Mon Sep 5 14:50:57 CEST 2016, 1473079883483,text output

, 0
Mon Sep 5 14:51:07 CEST 2016, 1473079893489,text output

, 0

我希望 set pagesize 0 从结果中删除所有这样的尾部换行,但无论如何在每个查询之后似乎都有两个换行,我似乎无法摆脱它无论我尝试什么。假脱机查询给出相同的结果。

我考虑改为在 sqlplus-session 中循环,但是由于脚本必须或多或少地永久运行,我担心这会永久保留一个连接槽用于其他功能上毫无意义的目的,这是不可取的。根据需要打开和关闭它似乎更明智。我根本没有测试过这种方法,主要是出于这个原因。

我希望避免对日志进行后期处理,因为我不知道其中可能会弹出什么样的错误条目,所以稍后对其进行美化感觉就像一个不必要的正则表达式噩梦。

对于如何使输出干净利落地排在一行上,没有不必要的换行和空格,同时确保不会丢失任何最终错误,有没有人有任何建议?

最佳答案

这有点变通,因为它实际上并没有解决我仍然无法解释的换行问题,但是一个非常简单的解决方案是将 sqlplus 输出直接存储到bash 变量,而不是尝试直接从 sqlplus 打印到日志,并将其作为任何其他变量回显。

基本上,我必须在上面的脚本中进行更改,将 sqlplus 命令包装在变量 QUERY_OUTPUT=$() 中并删除输出的管道:

while true; do

SECONDS=0
timestamp=$(date) 
echo -n "$timestamp, " >> $LOG_PATH

QUERY_RESULT=$(sqlplus -s $database << EOF
    whenever sqlerror exit sql.sqlcode

    set echo off
    set heading off
    set linesize 1000
    set pagesize 0
    set numformat 9999999999999
    set colsep ', '
    set null null

    SELECT TIME, BROKER_NAME FROM ACTIVEMQ_LOCK;
    exit;
EOF
)

echo $QUERY_RESULT, $SECONDS seconds elapsed >> $LOG_PATH

sleep $sleep_duration
done

我自己偶然发现了这个解决方案,同时花了几个小时尝试记录和验证我首先在上述问题中尝试过和未尝试过的内容,经过一些测试后,它似乎运行良好。一切都干净、可控地打印在一行上,任何最终的错误似乎也干净地打印在这一行上。准确找到我要找的东西。

自从我找到解决方案以来,一开始就考虑过不问这个问题,但我认为其他人也可能会从中看到一些值(value),至少我没能找到任何明显的重复。还不如分享!

关于bash - 使用 sqlplus 轮询并将结果记录到文件强制换行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39334024/

相关文章:

python - Informix、pyodbc、Centos

oracle - 如何从批处理文件执行sql文件并将输出显示到屏幕

linux - 在新进程树中运行 Bash 脚本

C++ system() 导致 "Text file busy"错误

python - PIP 无法从命令行使用

php - 带有 ISP Config 3 的 Centos 6.4 中 phpmyadmin 的主 php.ini 文件

linux - 测试命令时参数的语法

linux - 该脚本如何将十六进制转换为 ascii?

sql - 如何最好地重新创建 Oracle 数据库?

sql - Backspace 在 sqlplus 命令行中不起作用