Search code examples
oracle-databaseawktnsnames

Best means to parse TNSNAMES.ORA using awk


I have a function I built to parse Tnsnames.ora files. My question is there a better awk statement / query that will give me the results I want.

this is the statement I want to refine so I'll have a shorter code segment:
awk "BEGIN{found=0}/${entry}/{found=1} {if (found) print }")

I'd like to get rid of the for loop and use AWK to search and find the individual TNSNAME. Currently I'm counting thru the results of the awk command until I reach the last ) for the passed name.

findTnsname()
{
#!/bin/ksh
#inputs:
# $1: stanza title
# $2: Fully qualified input filename
#$3 set to yes will echo how many were found
tnsnames=$(cat $2)
entries=$(echo "$tnsnames"| grep -i "$1.*="| awk '{print $1}')
eNames=$(echo "$entries" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/,/g')
ecount=$(echo "$entries" | wc -l | awk '{print $1}')
if [ "$3" = "yes" ] ; then
  echo "# found ${ecount} entries -  ${eNames} "
fi
for entry in $entries
{
  #echo "#searching for ${entry}"
  tt=$(echo "$tnsnames" | awk "BEGIN{found=0}/${entry}/{found=1} {if (found) print }")
  t=0     # t for target, means the stanza has been found
  open_parens=0
  close_parens=0
  if [[ -n $tt ]] ; then
    echo "$tt" | while read -r i; do
            if(( t == 1 )); then
                    echo "$i"
                    newline_ck=$(echo "$i" | egrep "^$" | wc -l | awk '{print $1}') 
                    if(( newline_ck > 0 )); then
                            t=0
                            break
                    elif(( open_parens == close_parens && open_parens != 0 )); then
                            t=0

                    else
                            (( open_parens += $(echo "$i" | awk -F"(" '{print NF-1}') ))
                            (( close_parens += $(echo "$i" | awk -F")" '{print NF-1}') ))
                            #echo "# open ${open_parens} close ${close_parens} t ${t}"
                    fi
            else
                    t=$(echo "$i" | egrep -i "^$entry" | wc | awk '{print $1}')
                    if(( t == 1 )); then
                            echo "$i"
                    fi
            fi
    done 
   else
     echo "$entry does not exist in $2"
   fi
 } 
}

Results look like this: findTnsname abc "$ORACLE_HOME/network/admin/tnsnames.ora"

ABC_USR.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hosta.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ABC_usr)
)
)

ABCT.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostb.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ABCt)
)
)

sample input

DEF_USR.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hosta.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = DEF_USR)
)
)

DEFT.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostb.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = DEFT)
)
)

DEF_USR.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostc.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = DEF_USR)
)
)

DEFT.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostd.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = DEFT)
)
)
GHI_USR.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hoste.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = GHI_USR)
)
)

GHIT.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostf.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = GHIT)
)
)
ABC_USR.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hosta.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ABC_usr)
)
)

ABCT.some.company.com =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostb.some.company.com)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ABCt)
)
)

Solution

  • This might be what you're looking for, depending on the answers to the questions I asked in the comments under your question:

    If your input records always have blank lines between them as you suggested in one comment then all you need is:

    $ awk -v key='abc' -v RS= -v ORS='\n\n' 'tolower($0)~tolower(key)' file
    

    otherwise if they sometimes don't as in your provided sample input:

    $ cat tst.awk
    !NF { next }
    !/[()]/ { prt(); rec="" }
    { rec = rec $0 ORS }
    END { prt() }
    function prt() {
        if ( tolower(rec) ~ tolower(key) ) {
            print rec
        }
    }
    
    $ awk -v key='abc' -f tst.awk file
    ABC_USR.some.company.com =
    (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = hosta.some.company.com)(PORT = 1521))
    (LOAD_BALANCE = yes)
    (CONNECT_DATA =
    (SERVER = DEDICATED)
    (SERVICE_NAME = ABC_usr)
    )
    )
    
    ABCT.some.company.com =
    (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = hostb.some.company.com)(PORT = 1521))
    (LOAD_BALANCE = yes)
    (CONNECT_DATA =
    (SERVER = DEDICATED)
    (SERVICE_NAME = ABCt)
    )
    )
    

    EDIT - something else to consider for more control over where to search in which fields and what to print:

    $ cat tst.awk
    BEGIN { FS=RS; RS=""; ORS="\n" }
    {
        delete f
    
        f["NAME"] = $1
        sub(/[[:space:]]*=.*/,"",f["NAME"])
    
        for (i=2; i<=NF; i++) {
            n = split($i,tmp,/[ =()]+/)
            for (j=n-2; j>1; j-=2) {
                f[tmp[j]] = tmp[j+1]
            }
        }
    
        prt()
    }
    
    function prt() {
        for (tag in f) {
            print tag "=<" f[tag] ">"
        }
        print "----"
    }
    

    .

    $ awk -f tst.awk file
    LOAD_BALANCE=<yes>
    HOST=<hosta.some.company.com>
    PROTOCOL=<TCP>
    NAME=<DEF_USR.some.company.com>
    SERVICE_NAME=<DEF_USR>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hostb.some.company.com>
    PROTOCOL=<TCP>
    NAME=<DEFT.some.company.com>
    SERVICE_NAME=<DEFT>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hostc.some.company.com>
    PROTOCOL=<TCP>
    NAME=<DEF_USR.some.company.com>
    SERVICE_NAME=<DEF_USR>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hostd.some.company.com>
    PROTOCOL=<TCP>
    NAME=<DEFT.some.company.com>
    SERVICE_NAME=<DEFT>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hoste.some.company.com>
    PROTOCOL=<TCP>
    NAME=<GHI_USR.some.company.com>
    SERVICE_NAME=<GHI_USR>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hostf.some.company.com>
    PROTOCOL=<TCP>
    NAME=<GHIT.some.company.com>
    SERVICE_NAME=<GHIT>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hosta.some.company.com>
    PROTOCOL=<TCP>
    NAME=<ABC_USR.some.company.com>
    SERVICE_NAME=<ABC_usr>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----
    LOAD_BALANCE=<yes>
    HOST=<hostb.some.company.com>
    PROTOCOL=<TCP>
    NAME=<ABCT.some.company.com>
    SERVICE_NAME=<ABCt>
    SERVER=<DEDICATED>
    PORT=<1521>
    ----