如何在bash脚本中使用正则表达式对测试求反?


173

我想使用GNU bash(版本4.0.35(1)-发行版(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

Answers:


193

您说对了,只需在!和之[[类之间放置一个空格if ! [[


14
Oye vey!就在我安全地避开perl的星系间特殊角色疯狂时,我发现自己迷失在bash空间(布局)中!(我感到恐惧像蟒蛇一样挤压肠子。)谢谢!
David Rogers 2010年

126

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

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

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

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

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


啊,谢谢你关于锚定的提醒。使用bash或混合变量名的想法使bash初学者感到困惑,因为到目前为止我所看到的建议是使用大写。我理解您要表达的观点,但是我没有看到足够多的bash脚本示例让您满意地偏离(对本书的理解)。
David Rogers 2010年

4
@anyoneis相信我们这一点。应避免使用用户定义的大写变量。bash中的所有变量都使用扩展,$因此没有理由将它们大写以使其脱颖而出。
SiegeX'1

我发现它if [[ ! $foo =~ bar ]]if ! [[ $foo =~ bar ]]更为安全,因为它可以更轻松地为if
CTodea

19

最安全的方法就是放!对于这样的正则表达式求反[[ ]]

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

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


9

是的,您可以取消测试,因为SiegeX已经指出。

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

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

(资源)


1
使用这种形式的另一个原因是它不会意外地匹配子字符串(例如,由于已经存在“ / usr / bin”,因此无法将“ / bin”添加到路径中)。
戈登·戴维森

我花了一段时间才了解左侧的冒号如何给了我想要的锚点。通过在要搜索的字符串中添加材料来减少模式的想法值得记住。我不明白为什么路径中的特殊字符会破坏正则表达式解决方案,但不会破坏bash模式解决方案。你可以给我一个例子吗?
大卫·罗杰斯

我认为这并非在所有情况下都能正常运行。上等恕我直言的正则表达式匹配
Felipe Alvarez

5

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

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.