正则表达式w / grep反对tnsnames.ora

时间:2016-04-14 21:35:24

标签: regex unix grep sh tns

我正在尝试从tnsnames.ora文件中打印出TNS条目的内容,以确保它在Oracle RAC环境中是正确的。

所以,如果我这样做:

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

我会回来的:

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

这就是我想要的。现在,当shell脚本被调用时,我有一个外部程序为JDBC连接字符串设置了一个环境变量:

export $DB_URL=@myhost.mydomain.com:1521/mydb

所以我需要从上面的字符串中获取TNS别名mydb.mydomain.com。我不确定如何进行多次匹配并使用正则表达式重新排序匹配并需要一些帮助。

grep @.+: $DB_URL 

我假设会得到

@myhost.mydomain.com:

但我正在寻找

mydb.mydomain.com

所以我被困在这一部分。如何获取TNS别名,然后将其与初始grep管道/组合以显示TNS条目的文本?

由于

更新

@ mklement0 @Walter A - 我尝试过你的方式,但它们并不是我想要的。

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

所有这些方法都让我回头:myhost.mydomain.com

我正在寻找的是:mydb.mydomain.com

2 个答案:

答案 0 :(得分:2)

注意:
- 为简便起见,以下命令使用bash / ksh / zsh here-string语法将字符串发送到stdin(<<<"$var")。如果您的shell不支持此功能,请改用printf %s "$var" | ... 功能

以下awk命令将从mydb.mydomain.com$DB_URL)中提取所需的字符串(@myhost.mydomain.com:1521/mydb):

awk -F '[@:/]' '{ sub("^[^.]+", "", $2); print $4 $2 }'  <<<"$DB_URL"
  • -F'[@:/]'告诉awk将输入分为@:/字段。根据您的输入,这意味着感兴趣的字段是第二个字段($2)的部分和第四个字段($4)。 sub()调用会从.中移除第一个基于$2的组件,并将print个调用组合在一起。

把它们放在一起:

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

您并不严格需要中间变量$domain,但为了清晰起见,我已添加了它。 请注意-F如何添加到grep以指定搜索字词应被视为文字,以便.之类的字符不是{\ n}}被视为正则表达式元字符。

或者,要获得更强大的匹配,请使用正则表达式,该正则表达式通过^锚定到该行的开头,并\ - 转义 .字符(使用shell parameter expansion)确保将其作为文字处理:

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

答案 1 :(得分:2)

您可以使用

获取字符串的一部分
# 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%:*}"

我已经跳过了另一个awk,它已经由@ mklement0给出了:

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

awk解决方案是直截了当的,如果你想在没有awk的情况下使用相同的方法,你可以做类似的事情

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

或丑陋的

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

这里发生了什么? 在介绍新的IFS后,我想取输入的第二个字。第一个和第三个单词被捕获在虚拟变量_中(您可以将它们命名为dummyvar1dummyvar2)。管道|创建了一个子流程,因此您需要()来保持读取并在同一过程中显示var url