在 Bash 脚本中转义精确 grep 条件的字符

在 Bash 脚本中转义精确 grep 条件的字符

我有一个用于在 Linux 中查找特定已安装软件包的基本脚本。如果未找到 -> 打印软件包。

我使用了grep -w,但是它不能正常与-角色配合使用。

例如,

dpkg -l | grep -w "rpm"

还会发现rpm-common

我找到了使用正则表达式的解决方案。问题是它在 Bash 脚本中不起作用。

解决方案:

dpkg -l | grep -E '(^|\s)string($|\s)'

健康)状况:

if [ `dpkg -l | grep -E '(^|\s)$i($|\s)' | wc -l` = 0 ]; then echo$i; fi

$i指的是数组值,例如arr[index]=$i

我需要使用哪些转义字符才能使条件起作用?

答案1

这里有两个问题:正如@AFH 指出的那样,\s是 Perl 简写,不是标准 POSIX 语法的一部分。表示它的标准方法是使用字符类[[:space:]]。第二个问题是变量引用不会在单引号内展开;您需要使用双引号(并转义$正则表达式的一部分)。

此外,还有一些风格建议:$( )通常比反引号更适合用于命令替换(它更容易阅读,并且没有反引号所具有的一些奇怪的转义语法怪癖)。但在这种情况下,您可以跳过命令扩展;而不是使用wc -l并与零进行比较以查看是否有任何匹配项,只需使用grep的退出状态作为测试(以及-q阻止其打印匹配项的选项)。此外,请务必双引号引用变量引用(例如在命令中echo)。

以下是我建议的重写版本:

if dpkg -l | grep -Eq "(^|[[:space:]])$i(\$|[[:space:]])"; then echo "$i"; fi

编辑:正如 igor 在评论中指出的那样,这不适用于包含正则表达式元字符的包名称(如 g++-5)。可以预处理包名称以转义元字符,但这相当混乱。但有一种更简单的方法:如果您使用的是 bash(而不是其他 shell),则可以使用 bash 的本机正则表达式功能直接进行匹配:

if [[ "$(dpkg -l)" =~ (^|[[:space:]])"$i"(\$|[[:space:]]) ]]; then echo "$i"; fi

其之所以有效,是因为$i模式中间的 用双引号引起来,这告诉 bash 将其作为文字字符串进行匹配(即忽略其中的任何正则表达式元字符)。

答案2

扩展正则表达式不支持\s,但 Perl RE 支持,因此请尝试使用-P而不是-E

dpkg -l | grep -P '(^|\s)rpm($|\s)'

此引用了解更多信息。

手册grep上说这-P是实验性的,但它在 Ubuntu 16.04 上对我有用。

相关内容