仅使用 awk 或其他文件处理实用程序处理文件的 UNIX(AIX) 脚本

UNIX(AIX) script to process a file using only awk or other file processing utilities

我的任务是编写一个脚本来过滤来自 MQ 运行mqsc 命令的输入并将输出重定向到另一个文件。我一直在使用许多其他 Linux 命令通过管道传输在一起,它似乎在 Linux 中工作得很好,但我的经理需要 运行 AIX 系统上的脚本,因此 UNIX 操作系统。 我意识到许多 运行 在 Linux 上运行良好或在 Linux 上完成工作的命令在 UNIX 或基于 UNIX 的系统上会产生完全不同的输出。 运行mqsc 命令的输出如下所示:

5724-H72 (C) Copyright IBM Corp. 1994, 2009.  ALL RIGHTS RESERVED.
Starting MQSC for queue manager CNUMQ02B.


     1 : DISPLAY QLOCAL(*) CURDEPTH
AMQ8409: Display Queue details.
   QUEUE(ADEXA.AOM.REPLY.MR.QL)            TYPE(QLOCAL)
   CURDEPTH(0)                          
AMQ8409: Display Queue details.
   QUEUE(ADEXA.AOM.REPLY.QL)               TYPE(QLOCAL)
   CURDEPTH(0)                          
AMQ8409: Display Queue details.
   QUEUE(ADEXA.ERROR.QL)                   TYPE(QLOCAL)
   CURDEPTH(0)                          
AMQ8409: Display Queue details.
   QUEUE(ADEXA.FACT.OUT.QL)                TYPE(QLOCAL)
   CURDEPTH(0)
AMQ8409: Display Queue details.
   QUEUE(ADW.REMAN.XREF.ERR.QL)            TYPE(QLOCAL)
   CURDEPTH(14)
AMQ8409: Display Queue details.
   QUEUE(SAPNA.MESS.CRITICAL.CLASS.RESUME.QL)
   TYPE(QLOCAL)                            CURDEPTH(123)
One MQSC command read.
No commands have a syntax error.
All valid MQSC commands were processed.

我基本上需要做的只是在同一行显示队列名称、一个空格,然后是队列深度,没有尾随空格,文件开头或结尾没有换行符,所以它将类似于一个以空格作为分隔符的 csv 文件。我还需要过滤掉队列深度等于 0 的队列,因此输出将如下所示:

ADW.REMAN.XREF.ERR.QL 14

正如我所说,我在 Linux 上尝试了很多命令,但我不了解哪些命令和标志在 UNIX 和 Linux 上实际上或多或少地工作,我的经理今天想要这个,所以如果你有机会读到这篇文章,我要求你至少指导我使用什么来尝试解决它:)谢谢。

这是我在Linux中写的:

head -n -3 "" | 
tail -n +6 | 
sed '/AMQ8409: Display Queue details./d' | 
sed 's/TYPE(QLOCAL)//g' | 
tr -d ' \t\r\f' | 
awk 'NR%2{printf "%s ",[=12=];next;}1' | 
sed '/CURDEPTH(0)/d' | 
awk '{gsub(/QUEUE(/, ""); gsub(/CURDEPTH(/, ""); gsub(/)/, ""); print}' |
sort -nk2 

试试这个更简单的命令..

sed -n -e 's/.*QUEUE(\([^)]*\)).*//p' -e 's/.*CURDEPTH(\([0-9]*\)).*//p' \
   | paste -d ' ' - - \
   | grep -v ' 0$'

使用 awk,可以相对容易地完成:

runmqsc "display qlocal(*) curdepth" | awk '
    /QUEUE\(/ {
        gsub(/^[^\(]*\(/, "", [=10=]);
        gsub(/\).*$/, "", [=10=]);
        qname = [=10=];
    }
    /CURDEPTH\(/ {
        gsub(/^[^\(]*\(/, "", [=10=]);
        gsub(/\).*$/, "", [=10=]);
        print qname" "[=10=];
    }'

这基本上只是从包含 QUEUE( 的行中提取队列名称并将其存储以备后用。

当它找到包含 CURDEPTH( 的行时,它会以相同的方式提取深度,然后将其与存储的队列名称一起输出。

每个部分中的两个 gsub 调用看起来像 "black magic",但一旦您了解它们的含义,它们就很容易理解。第一个在行首找到一个模式,该模式由最大数量的非 ( 字符和后跟 ( 字符组成,然后将其替换为空。

第二个类似,但它删除了最大的序列“),后跟任何字符到行尾”。

$ awk '/QUEUE|CURDEPTH\(/ {                            # on matching records
           gsub(/^[^(]+\(|).*$/,"");                   # remove unwanted parts
           printf "%s%s", [=10=], ([=10=]~/^[0-9]+$/?ORS:OFS)  # print ORS after depth
       }' file
ADEXA.AOM.REPLY.MR.QL 0
ADEXA.AOM.REPLY.QL 0
ADEXA.ERROR.QL 0
ADEXA.FACT.OUT.QL 0
ADW.REMAN.XREF.ERR.QL 14

这是一个不使用 gsub:

awk -F "[()]" '/QUEUE/ {quename=} /CURDEPTH\(/ {print quename, } '

与其使用 "head"、"tail" 和 "sed" 删除不需要的行,不如使用 grep 删除您想要的行。我不确定这些选项中的哪一个适用于 AIX,但我应该相信它们。

grep -B 1 CURDEPTH 
grep -A 1 QUEUE 
grep -e QUEUE -e CURDEPTH 

接下来,加入并格式化行:

sed 's#.*QUEUE(\([^)]*\)).*\n.*CURDEPTH(\([0-9]*\)).*# #'

如果不能正常工作,请尝试使用“\r”而不是“\n”。

最后,删除深度为 0 的所有行(2 个选项):

grep -v " 0$"
sed '# 0$#d'

我对这种形式的 sed 不是很熟悉 - 我从你的代码示例中提取了它 - 但它看起来很简单所以应该可以工作。

所有这些命令都是关于您可以获得的最基本形式的,因此在任何 *nix 系统上都应该同样有效。希望。最开始的grep和sed是风险最高点。

这对我在 AIX 上有效以获取您需要的输出,它使用 IBM MQ 的 WHERE 子句将输出限制为 CURDEPTH 大于 0 的队列:

echo "DIS QL(*) WHERE(CURDEPTH GT 0)" | runmqsc <qmgr> | sed -e 's/\((.*)\)  *\(.*\)/\
/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)//g' -e 's/^\(AMQ[0-9][0-9]*:\).*$//g' | awk -F '[()]' -v OFS=" " 'function printValues() { if ("QUEUE" in p) { print p["QUEUE"], p["CURDEPTH"] } } /AMQ8409:/ { printValues(); for (i in p) { delete p[i] }; next } { p[] =  } END { printValues() }'

注意上面是两行,第一行末尾的\允许sed命令替换为嵌入的新行。 awk printValues 语法来自@mike.dld 对此post“”的回答。我不得不用 for (i in p) { delete p[i] } 替换他的 delete p 因为 AIX awk 不支持其他语法。

如果您想 运行 使用文件作为输入,请使用以下命令:

cat file | sed -e 's/\((.*)\)  *\(.*\)/\
/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)//g' -e 's/^\(AMQ[0-9][0-9]*:\).*$//g' | awk -F '[()]' -v OFS=" " 'function printValues() { if ("QUEUE" in p) { print p["QUEUE"], p["CURDEPTH"] } } /AMQ8409:/ { printValues(); for (i in p) { delete p[i] }; next } { p[] =  } END { printValues() }' | grep -v ' 0$'

很容易向输出添加任意数量的属性。如果你想在未来扩展它,你只需为每个需要的属性向 awk 命令添加更多条目,如下所示:, p["ATTR1"], p["ATTR2"]

MAXDEPTH为例:

echo "DIS QL(*) WHERE(CURDEPTH GT 0)" | runmqsc <qmgr> | sed -e 's/\((.*)\)  *\(.*\)/\
/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)//g' -e 's/^\(AMQ[0-9][0-9]*:\).*$//g' | awk -F '[()]' -v OFS=" " 'function printValues() { if ("QUEUE" in p) { print p["QUEUE"], p["CURDEPTH"], p["MAXDEPTH"] } } /AMQ8409:/ { printValues(); for (i in p) { delete p[i] }; next } { p[] =  } END { printValues() }'

请注意,如果属性本身嵌入了括号,这个答案和其他答案可能会有问题,这在队列的 DESCR 字段中是可能的,并且是其他对象类型上的各种其他字段也是如此。一个常见的例子是 CHANNELCONNAME 属性。 CONNAME 使用格式 hostname(port) 因此显示为 CONNAME(hostname(port)).