简体   繁体   中英

Using Sed Awk Bash to populate variable in search

I have several xml files that contain multiple sections. One of the sections in these files is "PublishMgr". Below this section there are two lines containing server names and port. I need to extracts the servers and ports and place them into variables and run query against them. I really don't know any easy way to do this. I was thinking using awk and sed, but my knowledge of these are limited. Can you assist pls?
I have gotten as far as getting the lines printed. I could use awk -F to get host name and port number for the first entry , but not sure how to do it for second line? I like to do it in one sweep if possible and not do this query twice? Can this be done?

Please note the I want to assign the output to 4 distinct variable !

My Code

cat filename | grep -A6 PublishMgr | grep "Address\|BacKMeUp"

XML-FILE/TXT Only portion of the file

<<!--==========================================-->
<!--   PublishMgr                          -->
<!--==========================================-->

<goandpublishme>

<ClassPub name="buylimit" pers="Y">
<prime>host9:1000</prime>
<backup>host145:9999</backup>
</ClassPub>

Current Output

   <prime>host9:1000</prime>
   <backup>host145:9999</backup>

Desired Output like to assign the results to variable Please note the I want to assign the output to 4 "distinct" variables. So I can use them for further inquiry like a simple example will be cd abc/$srv1;grep ports $srv1.log. In short I need to have $srv1 $srv2 $port1 $port2

srv1=host9    
port1=1000    
srv1=host145
port2=9999  

This is directly catering to your desired output, and is based on the fact that you say your knowledge of sed and awk is limited.

If this is your current output

   <prime>host9:1000</prime>
   <backup>host145:9999</backup>

Then you could get the desired output by adding a sed command with multiple expressions, and iterating through the list of line match terms:

| sed -E -e "s/(^\s*)(<.[^>]*>)/srv$i=/g" -e "s/(<.[^>]*>)//g" -e "s/(:)/\nport$i=/g"

A breakdown of this is as follows:

-e "s/(^\\s*)(<.[^>]*>)/srv$i=/g"

  • (^\\s*) - Start of line followed by unlimited whitespaces
  • (<.[^>]*>) - these <> and anything in-between
  • /srv$i=/g - Replace with srv followed by increment number.

-e "s/(<.[^>]*>)//g" Remove leading spaces

-e "s/(:)/\\nport=/g" Replaces : with \\n (new line) and port=


Take this test file input.txt , which contains:

<<!--==========================================-->
<!--   PublishMgr                          -->
<!--==========================================-->

<goandpublishme>

<ClassPub name="buylimit" pers="Y">
<prime>host9:1000</prime>
<backup>host145:9999</backup>
</ClassPub>

Your line list is: prime backup

Iterate through a list of line matches

i=1 ; for predicate in prime backup ; do grep -P "$predicate" <input.txt | sed -E -e "s/(^\s*)(<.[^>]*>)/srv$i=/g" -e "s/(<.[^>]*>)//g" -e "s/(:)/\nport$i=/g" ; (( i++ )) ; done

Results:

srv1=host9
port1=1000
srv2=host145
port2=9999

To Actually Assign (Not Print):

OLDIFS="$IFS" ; IFS=$'\n' ; for line in "$(i=1 ; for predicate in prime backup ; do grep -P "$predicate" <input.txt | sed -E -e "s/(^\s*)(<.[^>]*>)/srv$i=/g" -e "s/(<.[^>]*>)//g" -e "s/(:)/\nport$i=/g" ; (( i++ )) ; done)" ; do eval "$line" ; done ; IFS="$OLDIFS"

Breakdown:

#!/bin/bash

OLDIFS="$IFS"                                  #Save current IFS just for good measure
IFS=$'\n'                                      #Set IFS to new-line
for line in "$(i=1
    for predicate in prime backup
        do grep -P "$predicate" <input.txt \
        | sed -E -e "s/(^\s*)(<.[^>]*>)/srv$i=/g"\
             -e "s/(<.[^>]*>)//g" \
             -e "s/(:)/\nport$i=/g"
             (( i++ ))
        done)"                                #The original script broken into lines
        do 
            eval "$line"                      #Actually assign the variables
        done
IFS="$OLDIFS"                                 #Restore IFS

echo "\$srv1 is: $srv1"                       #Print values of assigned variables
echo "\$srv2 is: $srv2"
echo "\$port1 is: $port1"
echo "\$port2 is: $port2"

In general, you should not use line-oriented tools like sed and awk to process XML data. You should use an XML-aware tool instead. Assuming that your document is indeed valid XML, you could use xmlstarlet to extract the information:

xmlstarlet sel -t -v 'concat("srv1=", substring-before(//ClassPub/prime, ":"))' -nl \
    -t -v 'concat("port1=", substring-after(//ClassPub/prime, ":"))' -nl publish.xml

Just replace prime with backup and adjust the strings accordingly. I suspect you might have meant srv2 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM