【问题标题】:Don't match regex when variable is empty变量为空时不匹配正则表达式
【发布时间】:2021-08-12 23:14:20
【问题描述】:

我有以下文件

more /etc/hosts
23.1.22.162 kafka01.dfg.com
23.1.22.155 kafka02.dfg.com
23.1.22.222 kafka03.dfg.com
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

我们想在kafka_name=""egrep 时捕获所有masterworker 机器,所以我们这样做了

kafka_name=""
egrep "\smaster|\sworker|\s$kafka_name"  /etc/hosts

但我们仍然得到包含 kafka 机器的主机

 egrep "\smaster|\sworker|\s$kafka_name"  /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
23.1.22.162 kafka01.dfg.com
23.1.22.155 kafka02.dfg.com
23.1.22.222 kafka03.dfg.com
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

不管怎样,当我们设置时

kafka_name="kafka"

我们也得到了 kafka 机器

egrep "\smaster|\sworker|\s$kafka_name"  /etc/hosts
23.1.22.162 kafka01.dfg.com
23.1.22.155 kafka02.dfg.com
23.1.22.222 kafka03.dfg.com
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

那么为什么我们设置

kafka_name=""

尽管$kafka_name 为空,它是否仍会从主机打印 kafka 机器?

【问题讨论】:

  • $kafka_name 为空时,您匹配的是一个空字符串,它匹配所有内容。
  • \s 如果它的意思是 [[:space:]] 是 PCRE 语法,而不是 ERE 语法。 egrep 根本不保证兑现它(某些版本可以,但标准不需要它)。
  • 一种解决方案是设置kafka_name="periodontic-manipulation" 或您确信不会出现在主机文件中的任何其他值。那么该替代方案将永远不会匹配任何东西,而不是匹配所有东西。一种更优雅的方式可能是egrep "\smaster|\sworker${kafka_name:+|\s}$kafka_name" /etc/hosts,它仅在$kafka_name 非空时添加|\s
  • 或者完全放弃grep,使用awkawk -v kafka_name="$kafka_name" '$2 == "master" || $2 == "worker" || $2 == kafka_name'
  • 请注意,POSIX 仅指定grep。使用grep -E 获得egrep 的功能(和grep -F 获得fgrep 的功能):此 grep 已以向上兼容的方式进行了增强,以提供历史记录的确切功能 egrep fgrep 命令也是如此。 … _旧的 egrep fgrep 命令可能会在未来很多年作为实现扩展得到支持,允许历史应用程序在不修改的情况下运行。

标签: bash shell awk grep


【解决方案1】:

仅供参考,egrep 已弃用,取而代之的是 grep -E

不过,请考虑使用 awk,以便对您想要表达的任何条件(不仅仅是正则表达式 - 条件)进行清晰、简单的控制,例如:

$ kafka_name=''
$ awk -v kafka_name="$kafka_name" '( $2 ~ /^(master|worker)/ ) || ( (kafka_name != "") && ($2 ~ ("^"kafka_name)) )' file
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

$ kafka_name='kafka02'
$ awk -v kafka_name="$kafka_name" '( $2 ~ /^(master|worker)/ ) || ( (kafka_name != "") && ($2 ~ ("^"kafka_name)) )' file
23.1.22.155 kafka02.dfg.com
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

以上内容可以在每个 Unix 机器上的任何 shell 中使用任何 awk。

不过,它使用的是正则表达式而不是字符串比较,就像在您的 egrep 命令中所做的那样,因此如果这些名称中的任何一个可以包含正则表达式元字符,您需要将它们转义或更改脚本以使用 @ 987654326@无处不在,而不是$2 ~ /^regexp/,例如:

$ awk -v kafka_name="$kafka_name" '(index($2,"master") == 1) || (index($2,"worker") == 1) || ( (kafka_name != "") && (index($2,kafka_name) == 1) )' file
23.1.22.155 kafka02.dfg.com
23.1.22.111 master01.dfg.com
23.1.22.239 master02.dfg.com
23.1.22.170 master03.dfg.com
23.1.22.167 worker01.dfg.com
23.1.22.165 worker02.dfg.com
23.1.22.112 worker03.dfg.com

【讨论】:

    【解决方案2】:

    $kafka_name 为空时,模式为"\smaster|\sworker|\s",最后一个替代匹配任何带空格的行,因此它匹配所有内容。

    一种选择是将$kafka_name 设置为您知道永远不会存在的东西而不是空字符串,例如

    kafka_name=kafkaXXXX
    

    另一种是$kafka_name只有在它不为空时才添加到模式中。

    pattern="\smaster|\sworker"
    if [ -n "$kafka_name" ]
    then pattern="$pattern|\s$kafka_name"
    fi
    egrep "$pattern" /etc/hosts
    

    【讨论】:

    • 正如我在对该问题的评论中指出的那样,另一种方式可能是egrep "\smaster|\sworker${kafka_name:+|\s}$kafka_name" /etc/hosts,如果$kafka_name 既不是空也不是未定义,它只会添加|\s
    • 使用\s 使这不必要地特别注意哪些grep 实现将与它一起使用。诚然,我们知道 OP 目前正在使用一个可以接受的实现,但它会使他们的代码更容易移植到其他平台以切换到 [[:space:]]
    猜你喜欢
    • 2015-07-06
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多