5

I have a task to write a script that will filter an input from an MQ runmqsc command and redirect the output into another file. I have been working around using many other Linux commands piped together and it seems to work just fine in Linux, but my manager needs to run the script on an AIX system, so UNIX operating system. I was made aware that many commands that run fine on Linux or get the job done in Linux will produce a totally different output on UNIX or UNIX-based systems. The output from the runmqsc command looks like this:

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.

What I basically need to do is only display the name of the queue, a whitespace, and then the queue depth on the same line, with no trailing whitespaces and no newline characters at the beginning or end of file, so that it will resemble a csv file with the whitespace as the separator. I also need to filter out queues that have a queue depth equal to 0, so the output will look like this:

ADW.REMAN.XREF.ERR.QL 14

As I said I tried many commands on Linux, but I have a lack of knowledge of what commands and flags actually work more or less the same on UNIX and Linux, and my manager wants this today, so if by any chance you read this I ask that you at least guide me what to use to try working it out :) Thanks.

This is what I wrote in 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 
JoshMc
  • 10,239
  • 2
  • 19
  • 38
Cristian Baciu
  • 133
  • 1
  • 2
  • 15
  • Yes I did, and whatever I tried worked totally different on AIX, I am now only able to use an online UNIX interpretor to try working it out because my manager was testing them on some AIX Enterprise system that I have no access too, but this is what I wrote: 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 – Cristian Baciu Jan 23 '17 at 06:46
  • Appreciate your attempt, but can you udpate it as part of the question? – Inian Jan 23 '17 at 06:47
  • Which `awk` version do you have? Is it `GNU Awk`? Can you print `awk --version` and paste it? – Inian Jan 23 '17 at 06:57
  • I cannot get the awk version since the server I must run the command on is an enterprise server i have no access to, so i will have to stick to it and test a bunch of these solutions when my manager will arrive. I appreciate everyone providing input, now I need to do a little bit of testing of my own to see which one works on AIX, will provide the upvote for the working solution after this. Thank you very much! – Cristian Baciu Jan 23 '17 at 07:39
  • I guess the problem am foreseeing is, You have made a bunch of attempts on a different machine (a `GNU` based system) which led us all to provide `GNU Awk` based solutions. Almost all of them might not (unsure, just a thought) work on `Awk` under `AIX` – Inian Jan 23 '17 at 07:48

6 Answers6

2

Try this simpler command..

sed -n -e 's/.*QUEUE(\([^)]*\)).*/\1/p' -e 's/.*CURDEPTH(\([0-9]*\)).*/\1/p' \
   | paste -d ' ' - - \
   | grep -v ' 0$'
Grisha Levit
  • 8,194
  • 2
  • 38
  • 53
  • 1
    and `grep -v " 0$"` – Walter A Jan 23 '17 at 17:40
  • @WalterA thanks, I missed that part of the requirement. Edited my answer to add your suggestion. – Grisha Levit Jan 23 '17 at 19:40
  • Sorry for late reply, I have been busy as hell last week and had close to no access to the AIX test server we use here, because my colleagues are doing some DB2 installations and testing stuff. This one works best, on large files too, not that queue lists would be large files, but I wanted to put it to the test. This is the first answer that worked. – Cristian Baciu Feb 02 '17 at 09:19
1
$ 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
James Brown
  • 36,089
  • 7
  • 43
  • 59
  • I don't have access to AIX atm so I can't assure compatibility with it. Let me know if it works. – James Brown Jan 23 '17 at 07:37
  • Seems there are not enough parameters in the printf statement... although it looks like there are... can normal print use the ternary operator like that? – Cristian Baciu Jan 23 '17 at 11:09
  • Not like that since I use it for removing the newline after the queue name. Oh, something went from with cut and paste. Try it now. – James Brown Jan 23 '17 at 11:27
1

Here's one that doesn't use gsub:

awk -F "[()]" '/QUEUE/ {quename=$2} /CURDEPTH\(/ {print quename, $2} '
chthonicdaemon
  • 19,180
  • 2
  • 52
  • 66
  • This one seems to work just fine but it hiccups once it gets to process queues that are of a greater length, like for example the queue SAPNA.MESS.CRITICAL.CLASS.RESUME.QL, it will not delete the QLOCAL word and will not print the queue depth at the end of the line. I am now trying out all the possible answers here, man this AIX server is so stripped down, it uses a buggy old korn shell... – Cristian Baciu Jan 23 '17 at 10:46
  • 1
    Please add a couple of these lines to your example. I can't really see why it wouldn't work. – chthonicdaemon Jan 23 '17 at 11:28
1

Rather than use "head" and "tail" and "sed" to remove unwanted lines, use grep to take the ones you do want. I am not sure which of these options will work on AIX, but they all should I believe.

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

Next, join and format the lines:

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

If that doesn't work properly, try using '\r' instead of '\n'.

Lastly, remove all lines with a depth of 0 (2 options):

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

I'm not very familiar with this form of sed - I pinched it from your code example - but it looks simple so should work.

All these commands are about the most basic form you can get so should work equally well on any *nix system. Hopefully. The initial grep and the sed are the highest points of risk.

AlastairG
  • 4,119
  • 5
  • 26
  • 41
  • You were right they were, AIX uses a totally different set of command line parameters for grep, to make your solution work I will get into how grep works in AIX and probably post something about it tomorrow or so. Thanks for replying. – Cristian Baciu Jan 23 '17 at 11:22
  • For clarity; with grep -A gives the specified number of lines after the matching line (as well as the matching line) and -B gives the lines before. The -e option allows you to specify multiple matches, and the -v option excludes matching lines. If you can find matching AIX options you should be good. – AlastairG Jan 23 '17 at 12:53
1

This works for me on AIX to get the output you require, this uses the IBM MQ's WHERE clause to restrict the output to queues with a CURDEPTH greater than 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() }'

Note that above is two lines, the \ at the end of the first line allows the sed command to replace with an embedded new line. The awk printValues syntax is from @mike.dld answer to this post "Print part of an array or a file and sort in shell". I had to replace his delete p with the for (i in p) { delete p[i] } since AIX awk did not support the other syntax.

If you want to run with a file as input use the following:

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$'

It is easy to add any number of attributes to the output. If you want to expand it in the future you just add more entries to the awk command for each attribute required like this: , p["ATTR1"], p["ATTR2"]

Using MAXDEPTH as an example:

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() }'

Note that this answer and probably others will have an issue if the attribute itself has embedded parenthesis, this is possible in the DESCR field of the queue and is true of various other fields on other objects types. One common example is the CONNAME attribute of a CHANNEL. The CONNAME uses the format hostname(port) so is displayed as CONNAME(hostname(port)).

Community
  • 1
  • 1
JoshMc
  • 10,239
  • 2
  • 19
  • 38
  • This works too, I have embedded Grisha's solution and yours into our test AIX server. – Cristian Baciu Feb 02 '17 at 09:21
  • @CristianBaciu, Did the command i provided fail on a large file? – JoshMc Feb 02 '17 at 14:21
  • No it did not fail, we do not have queue managers on this client that have an absurd amount of queues, and to be honest, from a noobie point of view, I don't think there are queue managers in production to have millions of queues.. are there? I don't know. – Cristian Baciu Feb 02 '17 at 16:57
  • @CristianBaciu in practice I have not come across any with millions, but have come across thousands. I have updated the answer with a few more details that you may find helpful. – JoshMc Feb 02 '17 at 17:49
0

With awk, that can be done relatively easily:

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

This basically just extracts the queue name from lines containing QUEUE( and stores them for later.

When it finds lines containing CURDEPTH(, it extracts the depth the same way then outputs that along with the stored queue name.

The two gsub calls in each section look like "black magic" but they're easy to understand once you know what they mean. The first finds a pattern at line start consisting of the largest number of non-( characters followed by a ( character, then replaces that with nothing.

The second is similar but it removes the largest sequence of ") followed by any characters to end of line".

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • This one seems to have the same problem that @chthonicdaemon has, on the case of queue names exceeding a certain amount of characters it does not remove QLOCAL from the line and neither does it print the quue depth. I am trying right now to see how can i modify this script... – Cristian Baciu Jan 23 '17 at 10:56