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

Regex w/grep against tnsnames.ora

我正在尝试从 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 别名,然后 pipe/combine 它与初始 grep 一起显示 TNS 条目的文本?

谢谢


更新:

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

echo "@myhost.mydomain.com:1521/mydb" | grep -Po "@\K[^:]*"
echo "@myhost.mydomain.com:1521/mydb" | sed 's/.*@\(.*\):.*//'
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  }'

所有这些方法让我回来了:myhost.mydomain.com

我要找的其实是:mydb.mydomain.com

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

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

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

将它们放在一起:

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

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

或者,为了更稳健的匹配,使用 regex 锚定到带有 ^\-[= 的行的开头52=]转义 . 个字符(使用 shell parameter expansion)以确保将它们作为文字处理:

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

您可以使用

获取字符串的一部分
# Only GNU-grep
echo "@myhost.mydomain.com:1521/mydb" | grep -Po "@\K[^:]*"
# or
echo "@myhost.mydomain.com:1521/mydb" | sed 's/.*@\(.*\):.*//'
# 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  }'

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)。管道 | 创建一个子进程,因此您需要 () 在同一进程中读取和显示变量 url