dave111
dave111

Reputation: 305

Regex w/grep against tnsnames.ora

I am trying to print out the contents of a TNS entry from the tnsnames.ora file to make sure it is correct from an Oracle RAC environment.

So if I do something like:

grep -A 4 "mydb.mydomain.com" $ORACLE_HOME/network/admin/tnsnames.ora 

I will get back:

mydb.mydomain.com =
(DESCRIPTION =
  (ADDRESS =
  (PROTOCOL = TCP)(HOST = myhost.mydomain.com)(PORT = 1521))
  (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME=mydb)))

Which is what I want. Now I have an environment variable being set for the JDBC connection string by an external program when the shell script gets called like:

export [email protected]:1521/mydb

So I need to get TNS alias mydb.mydomain.com out of the above string. I'm not sure how to do multiple matches and reorder the matches with regex and need some help.

grep @.+: $DB_URL 

I assume will get the

@myhost.mydomain.com:

but I'm looking for

mydb.mydomain.com

So I'm stuck at this part. How do I get the TNS alias and then pipe/combine it with the initial grep to display the text for the TNS entry?

Thanks


update:

@mklement0 @Walter A - I tried your ways but they are not exactly what I was looking for.

echo "@myhost.mydomain.com:1521/mydb" | grep -Po "@\K[^:]*"
echo "@myhost.mydomain.com:1521/mydb" | sed 's/.*@\(.*\):.*/\1/'
echo "@myhost.mydomain.com:1521/mydb" | cut -d"@" -f2 | cut -d":" -f1
echo "@myhost.mydomain.com:1521/mydb" | tr "@:" "\t" | cut -f2
echo "@myhost.mydomain.com:1521/mydb" | awk -F'[@:]' '{ print $2 }'

All these methods get me back: myhost.mydomain.com

What I am looking for is actually: mydb.mydomain.com

Upvotes: 2

Views: 1040

Answers (2)

mklement0
mklement0

Reputation: 439852

Note:
- For brevity, the commands below use bash/ksh/zsh here-string syntax to send strings to stdin (<<<"$var"). If your shell doesn't support this, use printf %s "$var" | ... instead.

The following awk command will extract the desired string (mydb.mydomain.com) from $DB_URL (@myhost.mydomain.com:1521/mydb):

awk -F '[@:/]' '{ sub("^[^.]+", "", $2); print $4 $2 }'  <<<"$DB_URL"
  • -F'[@:/]' tells awk to split the input into fields by either @ or : or /. With your input, this means that the field of interest are part of the second field ($2) and the fourth field ($4). The sub() call removes the first .-based component from $2, and the print call pieces together the result.

To put it all together:

domain=$(awk -F '[@:/]' '{ sub("^[^.]+", "", $2); print $4 $2 }'  <<<"$DB_URL")
grep -F -A 4 "$domain" "$ORACLE_HOME/network/admin/tnsnames.ora"

You don't strictly need intermediate variable $domain, but I've added it for clarity. Note how -F was added to grep to specify that the search term should be treated as a literal, so that characters such as . aren't treated as regex metacharacters.

Alternatively, for more robust matching, use a regex that is anchored to the start of the line with ^, and \-escape the . chars (using shell parameter expansion) to ensure their treatment as literals:

grep -A 4 "^${domain//./\.}" "$ORACLE_HOME/network/admin/tnsnames.ora"

Upvotes: 2

Walter A
Walter A

Reputation: 20032

You can get a part of a string with

# Only GNU-grep
echo "@myhost.mydomain.com:1521/mydb" | grep -Po "@\K[^:]*"
# or
echo "@myhost.mydomain.com:1521/mydb" | sed 's/.*@\(.*\):.*/\1/'
# or
echo "@myhost.mydomain.com:1521/mydb" | cut -d"@" -f2 | cut -d":" -f1
# or, when the string already is in a var
echo "${DB_URL#*@}" | cut -d":" -f1
# or using a temp var
tmpvar="${DB_URL#*@}"
echo "${tmpvar%:*}"

I had skipped the alternative awk, that was given by @mklement0 already:

echo "@myhost.mydomain.com:1521/mydb" | awk -F'[@:]' '{ print $2 }'

The awk solution is straight-forward, when you want to use the same approach without awk you can do something like

echo "@myhost.mydomain.com:1521/mydb" | tr "@:" "\t" | cut -f2

or the ugly

echo "@myhost.mydomain.com:1521/mydb" | (IFS='@:' read -r _ url _; echo "$url")

What is happening here? After introducing the new IFS I want to take the second word of the input. The first and third word(s) are caught in the dummy var's _ (you could have named them dummyvar1 and dummyvar2). The pipe | creates a subprocess, so you need ()to hold reading and displaying the var url in the same process.

Upvotes: 2

Related Questions