如何在 bash 脚本中使用正则表达式否定测试?

Posted

技术标签:

【中文标题】如何在 bash 脚本中使用正则表达式否定测试?【英文标题】:How do I negate a test with regular expressions in a bash script? 【发布时间】:2011-05-31 08:59:01 【问题描述】:

使用 GNU bash(版本 4.0.35(1)-release (x86_64-suse-linux-gnu),我想用正则表达式否定一个测试。例如,我想有条件地添加一个路径到PATH 变量,如果路径不存在,如:

TEMP=/mnt/silo/bin
if [[ $PATH =~ $TEMP ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ $PATH =~ $TEMP ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ $PATH =~ $TEMP ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

我确信有一百万种方法可以做到这一点,但我想知道是否可以以某种方式否定条件,例如(错误的):

TEMP=/mnt/silo/bin
if ![[ $PATH =~ $TEMP ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ $PATH =~ $TEMP ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ $PATH =~ $TEMP ]] ; then PATH=$PATH:$TEMP; fi
export PATH

【问题讨论】:

【参考方案1】:

你说得对,只需在 ![[ 之间添加一个空格,例如 if ! [[

【讨论】:

哎呀!就在我安全地避开 perl 的星际特殊字符疯狂时,我发现自己迷失在 bash 空间(放置)中! (我感到恐惧像蟒蛇一样挤压我的肠道。)谢谢! 你确定它总是在[[之前而不是在里面,比如if [[ ! "$value" =~ $regex ]];吗?例如,如果在外面,Sublime Text 会奇怪地突出显示它:i.imgur.com/AQWuFtf.png【参考方案2】:

您也可以将感叹号放在括号内:

if [[ ! $PATH =~ $temp ]]

但您应该锚定您的模式以减少误报:

temp=/mnt/silo/bin
pattern="(^|:)$temp(:|$)"
if [[ ! "$PATH" =~ $pattern ]]

它在开头或结尾(或两者都)查找以冒号开头或结尾的匹配项。我建议习惯使用小写或混合大小写的变量名称,以减少名称与 shell 变量发生冲突的机会。

【讨论】:

啊,谢谢关于锚定的提醒。使用小写或混合变量名的想法会让 bash 初学者感到困惑,因为到目前为止我看到的建议是使用大写。我理解你的意思,但我没有看到足够多的 bash 脚本示例来让我觉得偏离(我的理解)食谱很舒服。 @anyoneis 信任我们。应避免使用用户定义的大写变量。 bash 中的所有变量都以$ 扩展,因此没有理由将它们大写以使其突出。 我发现if [[ ! $foo =~ bar ]]if ! [[ $foo =~ bar ]] 更安全,因为它更容易为if 引入更多条件【参考方案3】:

最安全的方法是把 !对于[[ ]] 中的正则表达式否定,如下所示:

if [[ ! $STR =~ YOUR_REGEX ]]; then

否则它可能会在某些系统上失败。

【讨论】:

【参考方案4】:

是的,正如SiegeX 已经指出的那样,您可以否定测试。

但是,您不应该为此使用正则表达式 - 如果您的路径包含特殊字符,它可能会失败。试试这个:

[[ ":$PATH:" != *":$1:"* ]]

(Source)

【讨论】:

使用这种形式的另一个原因是它不会意外匹配子字符串(例如,无法将“/bin”添加到路径中,因为“/usr/bin”已经存在)。 我花了一段时间才明白左边的冒号是如何给我想要的锚定的。通过向要搜索的字符串添加材料来减少模式的想法值得记住。我不明白为什么路径中的特殊字符会破坏正则表达式解决方案而不是 bash 模式解决方案。可以举个例子吗? 我不认为这在所有情况下都能可靠地工作。高级恕我直言中的正则表达式匹配【参考方案5】:

我喜欢在这种情况下不使用条件运算符来简化代码:

TEMP=/mnt/silo/bin
[[ $PATH =~ $TEMP ]] || PATH=$PATH:$TEMP

【讨论】:

以上是关于如何在 bash 脚本中使用正则表达式否定测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 bash 脚本中使用正则表达式?

正则表达式的否定

如何否定正则表达式中的特定单词? [复制]

bash:在 shell 脚本中使用正则表达式查找和 grep

Linux 第17天 bash,find,正则,命令历史

如何在 JavaScript 字符串替换中否定匹配正则表达式? [复制]