【问题标题】:UNIX(AIX) script to process a file using only awk or other file processing utilities仅使用 awk 或其他文件处理实用程序来处理文件的 UNIX(AIX) 脚本
【发布时间】:2017-06-07 14:48:57
【问题描述】:

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

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 "$1" | 
tail -n +6 | 
sed '/AMQ8409: Display Queue details./d' | 
sed 's/TYPE(QLOCAL)//g' | 
tr -d ' \t\r\f' | 
awk 'NR%2{printf "%s ",$0;next;}1' | 
sed '/CURDEPTH(0)/d' | 
awk '{gsub(/QUEUE(/, ""); gsub(/CURDEPTH(/, ""); gsub(/)/, ""); print}' |
sort -nk2 

【问题讨论】:

  • 是的,我做到了,无论我尝试什么,在 AIX 上的效果都完全不同,我现在只能使用在线 UNIX 解释器来尝试解决它,因为我的经理正在一些 AIX Enterprise 系统上测试它们我也没有访问权限,但这是我写的:head -n -3 "$1" |尾-n +6 | sed '/AMQ8409: 显示队列详情./d' | sed 's/TYPE(QLOCAL)//g' | tr -d ' \t\r\f' | awk 'NR%2{printf "%s",$0;next;}1' | sed '/CURDEPTH(0)/d' | awk '{gsub(/QUEUE(/, ""); gsub(/CURDEPTH(/, ""); gsub(/)/, ""); print}' | sort -nk2
  • 感谢您的尝试,但您能否将其作为问题的一部分进行更新?
  • 你有哪个awk 版本?是GNU Awk吗?可以打印awk --version并粘贴吗?
  • 我无法获得 awk 版本,因为我必须在其上运行命令的服务器是我无法访问的企业服务器,所以当我的经理将到达。我感谢每个提供意见的人,现在我需要自己做一些测试,看看哪个适用于 AIX,之后将为工作解决方案提供支持。非常感谢!
  • 我想我预见到的问题是,您已经在另一台机器(基于GNU 的系统)上进行了一系列尝试,这导致我们所有人都提供了基于GNU Awk 的解决方案。几乎所有人都可能无法(不确定,只是一个想法)在 Awk 下工作 AIX

标签: linux bash awk ibm-mq aix


【解决方案1】:

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

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

【讨论】:

  • grep -v " 0$"
  • @WalterA 谢谢,我错过了那部分要求。编辑了我的答案以添加您的建议。
  • 抱歉回复晚了,我上周一直忙得不可开交,几乎无法访问我们在这里使用的 AIX 测试服务器,因为我的同事正在做一些 DB2 安装和测试工作。这个效果最好,也适用于大文件,不是队列列表是大文件,但我想对其进行测试。这是第一个有效的答案。
【解决方案2】:

这里没有使用gsub

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

【讨论】:

  • 这个似乎工作得很好,但是一旦它处理更长的队列,例如队列 SAPNA.MESS.CRITICAL.CLASS.RESUME.QL,它就会打嗝不删除 QLOCAL 字并且不会在行尾打印队列深度。我现在在这里尝试所有可能的答案,伙计,这个 AIX 服务器是如此精简,它使用了一个有缺陷的旧 korn shell...
  • 请在您的示例中添加几行。我真的不明白为什么它不起作用。
【解决方案3】:

不要使用“head”、“tail”和“sed”来删除不需要的行,而是使用 grep 来获取您想要的行。我不确定这些选项中的哪一个适用于 AIX,但我都应该相信它们。

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

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

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

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

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

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

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

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

【讨论】:

  • 你是对的,他们是对的,AIX 为 grep 使用了一组完全不同的命令行参数,以使您的解决方案工作我将了解 grep 在 AIX 中的工作原理,并可能在明天左右发布一些关于它.感谢您的回复。
  • 为了清楚起见; with grep -A 在匹配行(以及匹配行)之后给出指定的行数,而 -B 给出之前的行。 -e 选项允许您指定多个匹配项,而 -v 选项排除匹配的行。如果你能找到匹配的 AIX 选项,你应该很好。
【解决方案4】:
$ awk '/QUEUE|CURDEPTH\(/ {                            # on matching records
           gsub(/^[^(]+\(|).*$/,"");                   # remove unwanted parts
           printf "%s%s", $0, ($0~/^[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

【讨论】:

  • 我无权访问 AIX atm,因此无法保证与它的兼容性。让我知道它是否有效。
  • 好像printf语句中的参数不够。。。虽然看起来有。。。正常打印可以这样用三元运算符吗?
  • 不像那样,因为我用它来删除队列名称后的换行符。哦,剪切和粘贴发生了一些事情。立即尝试。
【解决方案5】:

这适用于我在 AIX 上获得所需的输出,它使用 IBM MQ 的 WHERE 子句将输出限制为 CURDEPTH 大于 0 的队列:

echo "DIS QL(*) WHERE(CURDEPTH GT 0)" | runmqsc <qmgr> | sed -e 's/\((.*)\)  *\(.*\)/\1\
\2/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)/\1/g' -e 's/^\(AMQ[0-9][0-9]*:\).*$/\1/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[$1] = $2 } END { printValues() }'

请注意,上面是两行,第一行末尾的 \ 允许 sed 命令替换为嵌入的新行。 awk printValues 语法来自@mike.dld 对这篇文章“Print part of an array or a file and sort in shell”的回答。我不得不用for (i in p) { delete p[i] } 替换他的delete p,因为AIX awk 不支持其他语法。

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

cat file | sed -e 's/\((.*)\)  *\(.*\)/\1\
\2/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)/\1/g' -e 's/^\(AMQ[0-9][0-9]*:\).*$/\1/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[$1] = $2 } END { printValues() }' | grep -v ' 0$'

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

MAXDEPTH为例:

echo "DIS QL(*) WHERE(CURDEPTH GT 0)" | runmqsc <qmgr> | sed -e 's/\((.*)\)  *\(.*\)/\1\
\2/g' -e 's/^ *\([A-Z][A-Z]*[(][^)][^)]*[)]\)/\1/g' -e 's/^\(AMQ[0-9][0-9]*:\).*$/\1/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[$1] = $2 } END { printValues() }'

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

【讨论】:

  • 这也有效,我已将 Grisha 的解决方案和您的解决方案嵌入到我们的测试 AIX 服务器中。
  • @CristianBaciu,我提供的命令在大文件上失败了吗?
  • 不,它没有失败,我们在这个客户端上没有队列管理器,队列管理器数量荒谬,老实说,从菜鸟的角度来看,我认为没有生产中的队列管理器有数百万个队列.. 有吗?我不知道。
  • @CristianBaciu 在实践中我没有遇到过数百万,但遇到过数千。我已经更新了答案,提供了一些您可能会觉得有帮助的详细信息。
【解决方案6】:

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

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

这基本上只是从包含QUEUE( 的行中提取队列名称并存储它们以供以后使用。

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

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

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

【讨论】:

  • 这似乎和@chthonicdaemon 有同样的问题,在队列名称超过一定数量的字符的情况下,它不会从行中删除 QLOCAL,也不会打印队列深度。我现在正在尝试查看如何修改此脚本...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
相关资源
最近更新 更多