2

我正在尝试从 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

4

2 回答 2

2

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

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

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

把它们放在一起:

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

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

或者,为了更稳健的匹配,使用锚定到行首的正则表达式^,并且\-转义.字符(使用 shell参数扩展)以确保将它们视为文字:

grep -A 4 "^${domain//./\.}" "$ORACLE_HOME/network/admin/tnsnames.ora"
于 2016-04-14T21:43:04.853 回答
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%:*}"

我已经跳过了 @mklement0 给出的替代 awk:

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 之后,我想使用输入的第二个词。第一个和第三个单词被捕获在虚拟变量中_(您可以将它们命名为dummyvar1and dummyvar2)。管道|创建了一个子进程,因此您需要在同一进程中()保持读取和显示 var 。url

于 2016-04-14T21:59:21.237 回答