Parsing IBM MQ Series Runmqsc command output - bash

I'm using sed/awk to parse mq runmqsc output. We want to get certain fields displayed on a single line. This seems to be a straightforward sed/awk problem.
echo "display conn(*) ALL" |
runmqsc <BrokerName> |
awk '{ RS = "AMQ8276: Display Connection details." } ; { print $0 }' |
sed -e 's/( )/()/g'
5724-H72 (C) Copyright IBM Corp. 1994, 2009. ALL RIGHTS RESERVED.
Starting MQSC for queue manager .
1 : display conn(*) ALL
CONN(3923A95601000020)
EXTCONN(414D51435465737442726F6B65725553)
TYPE(CONN)
PID(9263) TID(1)
APPLDESC(WebSphere MQ Object Authority Manager)
APPLTAG(amqzfuma) APPLTYPE(SYSTEM)
ASTATE(NONE) CHANNEL()
CONNAME() CONNOPTS(MQCNO_FASTPATH_BINDING)
USERID(mqm) UOWLOG()
UOWSTDA() UOWSTTI()
UOWLOGDA() UOWLOGTI()
URTYPE(QMGR)
EXTURID(XA_FORMATID[00000000] XA_GTRID[] XA_BQUAL[])
QMURID(0.0) UOWSTATE(NONE)
This code:
echo "display conn(*) ALL" | runmqsc TestBrokerUS | awk '{ RS = "AMQ8276: Display Connection details." } ; { print $0 }' | sed -e 's/( )/()/g' |
sed -n -e 's/^.* CHANNEL(\(.*\).*) /\1/p' -e 's/^.* USERID(\(.*\).*)/\1/p' -e 's/^.* CONNOPTS(\(.*\).*)/\1/p' -e 's/^.* CONN(\(.*\).*)/\1/p' -e 's/^.* CONNAME(\(.*\).*)/\1/p'
Returns this:
3923A95601000020)
) CONNOPTS(MQCNO_FASTPATH_BINDING)
Need to parse out these fields on 1 line. Thoughts?

One option would be to replace the newlines from the output and then add one newline per each dis conn.
Example:
echo "dis conn(*) all" | runmqsc MQ8QMGR|sed ':a;N;$!ba;s/\n/ /g'|sed 's/UOWSTATE/\n/g'
Other option would be to store the values in variables and then print when you get the last attribute. Here is an example to parse dis qs output.
/QUEUE/{i1=index($1,"("); i2=index($1,")")-1; QUEUE=substr($1,i1+1,i2-i1);}
/CURDEPTH/{i1=index($1,"("); i2=index($1,")")-1; CURDEPTH=substr($1,i1+1,i2-i1);
i3=index($2,"("); i4=index($2,")")-1; IPPROCS=substr($2,i3+1,i4-i3);
}
/LGETDATE/{i1=index($1,"("); i2=index($1,")")-1; LGETDATE=substr($1,i1+1,i2-i1);
i3=index($2,"("); i4=index($2,")")-1; LGETTIME=substr($2,i3+1,i4-i3);
}
/LPUTDATE/{i1=index($1,"("); i2=index($1,")")-1; LPUTDATE=substr($1,i1+1,i2-i1);
i3=index($2,"("); i4=index($2,")")-1; LPUTTIME=substr($2,i3+1,i4-i3)
}
/MSGAGE/{i3=index($2,"("); i4=index($2,")")-1; MSGAGE=substr($2,i3+1,i4-i3);}
/OPPROCS/{i1=index($1,"("); i2=index($1,")")-1; OPPROCS=substr($1,i1+1,i2-i1);
i3=index($2,"("); i4=index($2,",")-1; QTIME=substr($2,i3+1,i4-i3);
i5=1; i6=index($3,")")-1; QTIME2=substr($3,i5,i6-i5+1);
}
/UNCOM/{
i1=index($1,"("); i2=index($1,")")-1; UNCOM=substr($1,i1+1,i2-i1);
if( QUEUE == "SYSTEM.CLUSTER.TRANSMIT.QUEUE" )
{
print date "|" QUEUE "|" CURDEPTH "|" LGETDATE "|" LGETTIME "|" LPUTDATE "|" LPUTTIME "|" MSGAGE "|" QTIME "," QTIME2 "|" UNCOM;
}
}

I use the following script:
#! /usr/bin/env gawk -f
#
# Parses output of 'runmqsc' command and prints a comma separated list of the
# attributes on one line per object.
#
# CAVEAT: Fails if '(' or ')' characters are in attribute values (e.g. DESC)
#
# Daniel Steinmann, Mai 2015
function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s }
function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
function trim(s) { return rtrim(ltrim(s)); }
BEGIN {
RS = "AMQ[0-9]+: [^.]*."
FS = "[()]"
}
{
# Filter out header
if (NR == 1) next
for (i = 1; i <= NF; i = i+2) {
key = trim($i)
value = trim($(i+1))
# Filter out empty lines and trailer
if (key ~ /[ ]/ || key == "") continue
if (i > 1) printf(", ")
printf("%s(%s)", key, value)
}
printf("\n")
}
It produces output like this:
$ echo "display conn(*) all | runmqsc MYQMGR | ./parse_runmqsc_output.gawk
CONN(F290EE5720001801), EXTCONN(414D51435858582E534232492E4D4149), ...
CONN(F290EE572009F312), EXTCONN(414D51435858582E534232492E4D4149), ...
You can easily adapt the gawk script to produce output the way you want.

Related

To split and arrange number in single inverted

I have around 65000 products codes in a text file.I wanted to split those number in group of 999 each .Then-after want each 999 number with single quotes separated by comma.
Could you please suggest how I can achieve above scenario through Unix script.
87453454
65778445
.
.
.
.
Till 65000 productscodes
Need to arrange in below pattern:
'87453454','65778445',
With awk:
awk '
++c == 1 { out = "\047" $0 "\047"; next }
{ out = out ",\047" $0 "\047" }
c == 999 { print out; c = 0 }
END { if (c) print out }
' file
Or, with GNU sed:
sed "
:a
\$bb
N
0~999{
:b
s/\n/','/g
s/^/'/
s/$/'/
b
}
ba" file
With Perl:
perl -ne '
sub pq { chomp; print "\x27$_\x27" } pq;
for (1 .. 998) {
if (defined($_ = <>)) {
print ",";
pq
}
}
print "\n"
' < file
Credit for Mauke perl#libera.chat
65000 isn't that many lines for awk - just do it all in one shot :
mawk 'BEGIN { FS = RS; RS = "^$"; OFS = (_="\47")(",")_
} gsub(/^|[^0-9]*$/,_, $!(NF = NF))'
'66771756','69562431','22026341','58085790','22563930',
'63801696','24044132','94255986','56451624','46154427'
That's for grouping them all in one line. To make 999 ones, try
jot -r 50 10000000 99999999 |
# change "5" to "999" here
rs -C= 0 5 |
mawk 'sub(".*", "\47&\47", $!(NF -= _==$NF ))' FS== OFS='\47,\47'
'36452530','29776340','31198057','36015730','30143632'
'49664844','83535994','86871984','44613227','12309645'
'58002568','31342035','72695499','54546650','21800933'
'38059391','36935562','98323086','91089765','65672096'
'17634208','14009291','39114390','35338398','43676356'
'14973124','19782405','96782582','27689803','27438921'
'79540212','49141859','25714405','42248622','25589123'
'11466085','87022819','65726165','86718075','56989625'
'12900115','82979216','65469187','63769703','86494457'
'26544666','89342693','64603075','26102683','70528492'
_==$NF checks whether right most column is empty or not,
—- i.e. whether there's a trailing edge sep that needds to be trimmed
If your input file only contains short codes as shown in your example, you could use the following hack:
xargs -L 999 bash -c "printf \'%s\', \"\$#\"; echo" . <inputFile >outputFile
Alternatively, you can use this sed command:
sed -Ene"s/(.*)/'\1',/;H" -e{'0~999','$'}'{z;x;s/\n//g;p}' <inputFile >outputFile
s/(.*)/'\1',/ wraps each line in '...',
but does not print it (-n)
instead, H appends the modified line to the so called hold space; basically a helper variable storing a single string.
(This also adds a line break as a separator, but we remove that later).
Every 999 lines (0~999) and at the end of the input file ($) ...
... the hold space is then printed and cleared (z;x;...;p)
while deleting all delimiter-linebreaks (s/\n//g) mentioned earlier.

awk bash recursive brackets id sed tr

A server provides a list of asset IDs separated by commas in square brackets after the date and colons :
20160420084726:-
20160420085418:[111783178, 111557953, 111646835, 111413356, 111412662, 105618372, 111413557]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085522:[111344871, 111394583, 111295547, 111379566, 111352520]
20160420090022:[111344871, 111394583, 111295547, 111379566, 111352520]
The format of the input log is:
timestamp:ads
Where:
timestamp is in the format YYYYMMDDhhmmss, and ads is a comma separated list of ad asset IDs surrounded by square brackets, or - if no ads were returned.
The first part of the task is to write a script that outputs, for each ten minute slice of the day:
Count of IDs that were returned
Count of unique IDs that were returned
Script should support a command line parameter to select whether unique or total IDs should be given.
Example output using the above log excerpt (in total mode):
20160420084:0
20160420085:26
20160420090:5
And in unique count mode it would give:
20160420084:0
20160420085:19
20160420090:5
I have tried this:
awk -F '[,:]' '
{
key = substr($1,1,11)"0"
count[key] += ($2 == "-" ? 0 : NF-1)
}
END {
PROCINFO["sorted_in"] = "#ind_num_asc"
for (key in count) print key, count[key]
}
' $LOGFILENAME | grep $DATE;
With the scripts given until now other scenarios fail. For example this one:
log file:
https://drive.google.com/file/d/1sXFvLyCH8gZrXiqf095MubyP7-sLVUXt/view?usp=sharing
The first few lines of the results should be:
nonunique:
20160420000:1
20160420001:11
20160420002:13
20160420003:16
20160420004:3
20160420005:3
20160420010:6
unique:
20160420000:1
20160420001:5
20160420002:5
20160420003:5
20160420004:3
20160420005:3
20160420010:4
$ cat tst.awk
BEGIN { FS="[]:[]+"; OFS=":" }
{
tot = unq = 0
time = substr($1,1,11)
if ( /,/ ) {
tot = split($2,tmp,/, ?/)
for ( i in tmp ) {
if ( !seen[time,tmp[i]]++ ) {
unq++
}
}
}
tots[time] += tot
unqs[time] += unq
}
END {
for (time in tots) {
print time, tots[time], unqs[time]
}
}
$ awk -f tst.awk file
20160420084:0:0
20160420085:26:19
20160420090:5:5
Massage to suit...
#!/bin/bash
while read; do
dts=$( echo "$REPLY" | cut -d: -f1 )
ids=$( echo "$REPLY" | grep -o '\[.*\]' )
if [ $? -eq 0 ]; then
ids=$( echo "$ids" | tr -d '[] ' | tr ',' '\n' | sort $1 )
count=$( echo "$ids" | wc -l )
else
count=0
fi
echo $dts: $count
done
Run like this:
./script.sh [-u] <input.txt

awk - piping string to external gfortran-built executable in unix

I have the following awk-script "create_grid.awk" which pipes a command through to an external exe (iri_win.exe/iri_unix.exe built with gfortran) and reads back the response via getline (creating a grid of values with two nested for-loops). Whereas everything works like a charm in windows the matter in the unix environment goes wrong.
!/bin/awk -f
BEGIN {
is_windows = 0;
if (index(tolower(ENVIRON["OS"]), "windows") > 0) {
is_windows = 1;
}
exit
}
{
}
END {
mystring=""
#myvar=""
#CMD = "cmdline | getline myvar"
#print "" > "iri_fortran_output_grid.txt"
for (j = -9 ; j <= -9; j+=2){
for (i = -2; i <= 2; i++){
pipe= "\"" j "," i ",0.300\n2017,823,0,12.750\n20200" "\""
#pipe= "\"49,12,0.300\n2017,823,1,12.750\n20200 \""
#pipe= "\"49,12,0.300\n2017,823,1,12.750\n20200\""
if (is_windows)
cmdline = "echo -e " pipe " | ./iri_win.exe"
else
cmdline = "echo -e " pipe " | ./iri_unix.exe"
print cmdline
if ( (cmdline | getline myvar) > 0 ) {
#close(cmdline | getline myvar)
print "latitude " j " , longitude " i " done, TEC: " myvar " ;"
}
else{
#close(cmdline | getline myvar)
print "error in latitude " j " , longitude " i
}
close(cmdline)
#close(getline)
#cmdline | getline myvar
#myvar = $0
mystring = mystring myvar " "
}
# print one line into result file
sub(/[ \t]+$/, "", mystring)
sub(/^[ \t]+/, "", mystring)
print mystring > "iri_fortran_output_grid.txt"
print "longitude " j " done"
mystring=""
fflush("iri_fortran_output_grid.txt")
fflush(stdout)
#close("iri_fortran_output_grid.txt")
}
}
Output of awk script in Unix OS:
loren32#nautilus:~/iri_exe_analysis$gawk -f ./create_grid.awk
At line 107 of file iri_4_tec_al_2.for (unit = 5, file = 'stdin')
Fortran runtime error: Bad real number in item 1 of list input
error in latitude -9 , longitude 0
echo -e "-9,1,0.300
2017,823,0,12.750
20200" | ./iri_unix.exe
...
Output in Unix OS only executing external exe :
loren32#nautilus:~/iri_exe_analysis$ echo -e "-9,1,0.300\n2017,823,1,12.750\n20200" | ./iri_unix.exe
18.452
As can be seen when I pipe my string via echo -e "stringcontent" to iri_unix.exe from bash in Unix it works but the call from within the awk script fails.
I suspect the quotes work differently in unix and somehow additional disturbing string data is sent to iri_unix.exe - hence the error message "Bad real number in item 1 of list input".
I wonder what is going wrong and how to correct my awk script to make it work in Unix OS. In Windows the script works fine
The workaround is to write
echo "..."
in the Unix Environment and leave out the -e option. That die the trick for me.

Parsing iw wlan0 scan output

I wrote wlan manager script to handle open/ad-hoc/wep/wpa2 networks. Now im trying to parse iw wlan0 scan output to get nice scan feature to my script. My goal is to get output like this :
SSID channel signal encryption
wlan-ap 6 70% wpa2-psk
test 1 55% wep
What i have achived already is output like this :
$ iw wlan0 scan | grep 'SSID\|freq\|signal\|capability' | tac
SSID: Koti783
signal: -82.00 dBm
capability: ESS Privacy ShortPreamble SpectrumMgmt ShortSlotTime (0x0531)
freq: 2437
I have been trying to study bash/sed/awk but havent found yet a way to achieve what im trying. So what is good way to achieve that?
Here is my final solution based of Sudo_O answer:
$1 == "BSS" {
MAC = $2
wifi[MAC]["enc"] = "Open"
}
$1 == "SSID:" {
wifi[MAC]["SSID"] = $2
}
$1 == "freq:" {
wifi[MAC]["freq"] = $NF
}
$1 == "signal:" {
wifi[MAC]["sig"] = $2 " " $3
}
$1 == "WPA:" {
wifi[MAC]["enc"] = "WPA"
}
$1 == "WEP:" {
wifi[MAC]["enc"] = "WEP"
}
END {
printf "%s\t\t%s\t%s\t\t%s\n","SSID","Frequency","Signal","Encryption"
for (w in wifi) {
printf "%s\t\t%s\t\t%s\t%s\n",wifi[w]["SSID"],wifi[w]["freq"],wifi[w]["sig"],wifi[w]["enc"]
}
}'
Output:
$ sudo iw wlan0 scan | awk -f scan.awk
SSID Frequency Signal Encryption
netti 2437 -31.00 dBm Open
Koti783 2437 -84.00 dBm WPA
WLAN-AP 2462 -85.00 dBm WPA
it's generally bad practice to try parsing complex output of programs intended for humans to read (rather than machines to parse).
e.g. the output of iw might change depending on the language settings of the system and/or the version of iw, leaving you with a "manager" that only works on your development machine.
instead you might use the same interface that iw uses to get it's information: the library backend libnl
you might also want to have a look at the wireless-tools (iwconfig, iwlist,...) that use the libiw library.
Here is an GNU awk script to get you going that grabs the SSIDs and the channel for each unique BSS:
/^BSS / {
MAC = $2
}
/SSID/ {
wifi[MAC]["SSID"] = $2
}
/primary channel/ {
wifi[MAC]["channel"] = $NF
}
# Insert new block here
END {
printf "%s\t\t%s\n","SSID","channel"
for (w in wifi) {
printf "%s\t\t%s\n",wifi[w]["SSID"],wifi[w]["channel"]
}
}
It should be easy for you to add the new blocks for signal and encryption considering all the studying you have been doing.
Save the script to file such as wifi.awk and run like:
$ sudo iw wlan0 scan | awk -f wifi.awk
The output will be in the formatted requested:
SSID channel
wlan-ap 6
test 1
Here is a simple Bash function which uses exclusively Bash internals and spawns only one sub-shell:
#!/bin/bash
function iwScan() {
# disable globbing to avoid surprises
set -o noglob
# make temporary variables local to our function
local AP S
# read stdin of the function into AP variable
while read -r AP; do
## print lines only containing needed fields
[[ "${AP//'SSID: '*}" == '' ]] && printf '%b' "${AP/'SSID: '}\n"
[[ "${AP//'signal: '*}" == '' ]] && ( S=( ${AP/'signal: '} ); printf '%b' "${S[0]},";)
done
set +o noglob
}
iwScan <<< "$(iw wlan0 scan)"
Output:
-66.00,FRITZ!Box 7312
-56.00,ALICE-WLAN01
-78.00,o2-WLAN93
-78.00,EasyBox-7A2302
-62.00,dlink
-74.00,EasyBox-59DF56
-76.00,BELAYS_Network
-82.00,o2-WLAN20
-82.00,BPPvM
The function can be easily modified to provide additional fields by adding a necessary filter into the while read -r AP while-loop, eg:
[[ "${AP//'last seen: '*}" == '' ]] && ( S=( ${AP/'last seen: '} ); printf '%b' "${S[0]},";)
Output:
-64.00,1000,FRITZ!Box 7312
-54.00,492,ALICE-WLAN01
-76.00,2588,o2-WLAN93
-78.00,652,LN8-Gast
-72.00,2916,WHITE-BOX
-66.00,288,ALICE-WLAN
-78.00,800,EasyBox-59DF56
-80.00,720,EasyBox-7A2302
-84.00,596,ALICE-WLAN08
I am using such solution for openwrt:
wlan_scan.sh
#!/bin/sh
sudo iw dev wlan0 scan | awk -f wlan_scan.awk | sort
wlan_scan.awk
/^BSS/ {
mac = gensub ( /^BSS[[:space:]]*([0-9a-fA-F:]+).*?$/, "\\1", "g", $0 );
}
/^[[:space:]]*signal:/ {
signal = gensub ( /^[[:space:]]*signal:[[:space:]]*(\-?[0-9.]+).*?$/, "\\1", "g", $0 );
}
/^[[:space:]]*SSID:/ {
ssid = gensub ( /^[[:space:]]*SSID:[[:space:]]*([^\n]*).*?$/, "\\1", "g", $0 );
printf ( "%s %s %s\n", signal, mac, ssid );
}
result
-62.00 c8:64:c7:54:d9:05 a
-72.00 70:72:3c:1c:af:17 b
-81.00 78:f5:fd:be:33:cb c
There is a bug in the awk script above.
The following code will not work if the SSID has spaces in the name. The received result will be the first token of the SSID name only.
$1 == "SSID:" {
wifi[MAC]["SSID"] = $2
}
When printing $0, $1, $2:
$0: SSID: DIRECT-82-HP OfficeJet 8700
$1: SSID:
$2: DIRECT-82-HP
One possibly solution is to take a substr of $0 which contains leading spaces, the token "SSID: " and the provided multi-token network name.
Any other suggestions?
I've taken awk code from Ari Malinen and reworked it a bit, because iw output is not stable and changes, also there are other issues like spaces in SSID. I put it on github in case if I'll change it in the future.
#!/usr/bin/env awk -f
$1 ~ /^BSS/ {
if($2 !~ /Load:/) { #< Escape "BBS Load:" line
gsub("(\\(.*|:)", "", $2)
MAC = toupper($2)
wifi[MAC]["enc"] = "OPEN"
wifi[MAC]["WPS"] = "no"
wifi[MAC]["wpa1"] = ""
wifi[MAC]["wpa2"] = ""
wifi[MAC]["wep"] = ""
}
}
$1 == "SSID:" {
# Workaround spaces in SSID
FS=":" #< Changing field separator on ":", it should be
# forbidded sign for SSID name
$0=$0
sub(" ", "", $2) #< remove first whitespace
wifi[MAC]["SSID"] = $2
FS=" "
$0=$0
}
$1 == "capability:" {
for(i=2; i<=NF; i++) {
if($i ~ /0x[0-9]{4}/) {
gsub("(\\(|\\))", "", $i)
if (and(strtonum($i), 0x10))
wifi[MAC]["wep"] = "WEP"
}
}
}
$1 == "WPA:" {
wifi[MAC]["wpa1"] = "WPA1"
}
$1 == "RSN:" {
wifi[MAC]["wpa2"] = "WPA2"
}
$1 == "WPS:" {
wifi[MAC]["WPS"] = "yes"
}
$1 == "DS" {
wifi[MAC]["Ch"] = $5
}
$1 == "signal:" {
match($2, /-([0-9]{2})\.00/, m)
wifi[MAC]["Sig"] = m[1]
}
$1 == "TSF:" {
gsub("(\\(|d|,)", "", $4)
match($5, /([0-9]{2}):([0-9]{2}):/, m)
day = $4
hour = m[1]
min = m[2]
wifi[MAC]["TSF"] = day"d"hour"h"min"m"
}
END {
for (w in wifi) {
if (wifi[w]["wep"]) {
if (wifi[w]["wpa1"] || wifi[w]["wpa2"])
wifi[w]["enc"] = wifi[w]["wpa1"]wifi[w]["wpa2"]
else
wifi[w]["enc"] = "WEP"
}
printf "%s:%s:%s:%s:%s:%s:%s\n", w, wifi[w]["SSID"], wifi[w]["enc"], \
wifi[w]["WPS"], wifi[w]["Ch"], wifi[w]["Sig"], wifi[w]["TSF"]
}
}
Output:
A5FEF2C499BB:test-ssid2:OPEN:no:9:43:0d00h00m
039EFACA9A8B:test-ssid2:WPA1:no:9:33:0d00h00m
038BF3C1988B:test-ssid2:WPA2:no:9:35:0d00h00m
028EF3C2997B:test-ssid2:WPA1:no:9:35:0d00h03m
if you wonder what if($2 !~ /Load:/) does, well on some routers there might be "BSS Load:" string.

Extracting multiple parts of a string using bash

I have a caret delimited (key=value) input and would like to extract multiple tokens of interest from it.
For example: Given the following input
$ echo -e "1=A00^35=D^150=1^33=1\n1=B000^35=D^150=2^33=2"
1=A00^35=D^22=101^150=1^33=1
1=B000^35=D^22=101^150=2^33=2
I would like the following output
35=D^150=1^
35=D^150=2^
I have tried the following
$ echo -e "1=A00^35=D^150=1^33=1\n1=B000^35=D^150=2^33=2"|egrep -o "35=[^/^]*\^|150=[^/^]*\^"
35=D^
150=1^
35=D^
150=2^
My problem is that egrep returns each match on a separate line. Is it possible to get one line of output for one line of input? Please note that due to the constraints of the larger script, I cannot simply do a blind replace of all the \n characters in the output.
Thank you for any suggestions.This script is for bash 3.2.25. Any egrep alternatives are welcome. Please note that the tokens of interest (35 and 150) may change and I am already generating the egrep pattern in the script. Hence a one liner (if possible) would be great
You have two options. Option 1 is to change the "white space character" and use set --:
OFS=$IFS
IFS="^ "
set -- 1=A00^35=D^150=1^33=1 # No quotes here!!
IFS="$OFS"
Now you have your values in $1, $2, etc.
Or you can use an array:
tmp=$(echo "1=A00^35=D^150=1^33=1" | sed -e 's:\([0-9]\+\)=: [\1]=:g' -e 's:\^ : :g')
eval value=($tmp)
echo "35=${value[35]}^150=${value[150]}"
To get rid of the newline, you can just echo it again:
$ echo $(echo "1=A00^35=D^150=1^33=1"|egrep -o "35=[^/^]*\^|150=[^/^]*\^")
35=D^ 150=1^
If that's not satisfactory (I think it may give you one line for the whole input file), you can use awk:
pax> echo '
1=A00^35=D^150=1^33=1
1=a00^35=d^157=11^33=11
' | awk -vLIST=35,150 -F^ ' {
sep = "";
split (LIST, srch, ",");
for (i = 1; i <= NF; i++) {
for (idx in srch) {
split ($i, arr, "=");
if (arr[1] == srch[idx]) {
printf sep "" arr[1] "=" arr[2];
sep = "^";
}
}
}
if (sep != "") {
print sep;
}
}'
35=D^150=1^
35=d^
pax> echo '
1=A00^35=D^150=1^33=1
1=a00^35=d^157=11^33=11
' | awk -vLIST=1,33 -F^ ' {
sep = "";
split (LIST, srch, ",");
for (i = 1; i <= NF; i++) {
for (idx in srch) {
split ($i, arr, "=");
if (arr[1] == srch[idx]) {
printf sep "" arr[1] "=" arr[2];
sep = "^";
}
}
}
if (sep != "") {
print sep;
}
}'
1=A00^33=1^
1=a00^33=11^
This one allows you to use a single awk script and all you need to do is to provide a comma-separated list of keys to print out.
And here's the one-liner version :-)
echo '1=A00^35=D^150=1^33=1
1=a00^35=d^157=11^33=11
' | awk -vLST=1,33 -F^ '{s="";split(LST,k,",");for(i=1;i<=NF;i++){for(j in k){split($i,arr,"=");if(arr[1]==k[j]){printf s""arr[1]"="arr[2];s="^";}}}if(s!=""){print s;}}'
given a file 'in' containing your strings :
$ for i in $(cut -d^ -f2,3 < in);do echo $i^;done
35=D^150=1^
35=D^150=2^

Resources