在 bash 的 if 条件中使用正则表达式
Posted
技术标签:
【中文标题】在 bash 的 if 条件中使用正则表达式【英文标题】:use regular expression in if-condition in bash 【发布时间】:2011-01-21 20:19:01 【问题描述】:我想知道在 bash 的 if 子句中使用正则表达式的一般规则?
这是一个例子
$ gg=svm-grid-ch
$ if [[ $gg == *grid* ]] ; then echo $gg; fi
svm-grid-ch
$ if [[ $gg == ^....grid* ]] ; then echo $gg; fi
$ if [[ $gg == ....grid* ]] ; then echo $gg; fi
$ if [[ $gg == s...grid* ]] ; then echo $gg; fi
$
为什么最后三个不匹配?
希望你能给出尽可能多的通用规则,而不仅仅是这个例子。
【问题讨论】:
【参考方案1】:if [[ $gg =~ ^....grid.* ]]
【讨论】:
您应该可以使用“.4”而不是“....”,即“^.4grid.*”。它可以更容易阅读和理解。【参考方案2】:使用
=~
对于正则表达式检查Regular Expressions Tutorial Table of Contents
【讨论】:
【参考方案3】:使用 glob 模式时,问号表示单个字符,星号表示零个或多个字符的序列:
if [[ $gg == ????grid* ]] ; then echo $gg; fi
使用正则表达式时,点表示单个字符,星号表示前面的零个或多个字符。所以“.*
”代表零个或多个任意字符,“a*
”代表零个或多个“a”,“[0-9]*
”代表零个或多个数字。另一个有用的(在许多中)是加号,它代表一个或多个前面的字符。因此“[a-z]+
”代表一个或多个小写字母字符(在 C 语言环境中 - 以及其他一些语言环境中)。
if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi
【讨论】:
那么字符串匹配有两种方式:glob模式和正则表达式? glob pettern 不仅用于文件名吗?在 bash 中,何时使用 glob 模式以及何时使用正则表达式?谢谢! @Tim: Globbing 在大多数或所有版本的 Bash 中都可用。正则表达式匹配仅在版本 3 及更高版本中可用,但我建议仅在 3.2 及更高版本中使用它。正则表达式比通配符多更通用。【参考方案4】:@OP,
glob pettern 不仅用于文件名吗?
不,“glob”模式不仅用于文件名。您也可以使用它来比较字符串。在您的示例中,您可以使用 case/esac 来查找字符串模式。
gg=svm-grid-ch
# looking for the word "grid" in the string $gg
case "$gg" in
*grid* ) echo "found";;
esac
# [[ $gg =~ ^....grid* ]]
case "$gg" in ????grid*) echo "found";; esac
# [[ $gg =~ s...grid* ]]
case "$gg" in s???grid*) echo "found";; esac
在 bash 中,什么时候使用 glob 模式,什么时候使用正则表达式?谢谢!
Regex 比“glob 模式”更通用和“方便”,但是除非您正在执行“globbing/extended globbing”无法轻松提供的复杂任务,否则没有必要使用 regex。 bash extglob )。有关扩展通配符,请参阅 here 和一些简单的示例 here。
OP 更新:使用正则表达式查找以 2 个字符(点“.”表示 1 个字符)后跟“g”的文件的示例
例如输出
$ shopt -s dotglob
$ ls -1 *
abg
degree
..g
$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done
abg
degree
..g
在上面,文件被匹配是因为它们的名称包含 2 个字符,后跟“g”。 (即..g
)。
globbing 的等效项是这样的:(查看reference 以了解?
和*
的含义)
$ for file in ??g*; do echo $file; done
abg
degree
..g
【讨论】:
感谢 ghostdog74。在高于 3.2 版本的 Bash 中,可以使用正则表达式来替换 glob 模式出现的任何地方吗?还是正则表达式只能在某些特殊情况下使用?例如,我发现“ls ??g”正在工作,而“ls ..g”却没有。 如果有需要,你可以使用正则表达式。由你决定。请注意,正则表达式语法与 shell 通配符语法不同。所以ls ..g
不起作用。您是在告诉 shell 查找名为 ..g
的文件。至于学习regex语法,可以试试perldoc perlretut
,perldoc perlrequick
,或者在命令行下info sed
。【参考方案5】:
使用grep
和基本的sh
内置函数为那些对更便携的解决方案感兴趣的人添加这个解决方案(独立于bash
版本;也适用于普通的旧sh
,在非Linux 平台等)
# GLOB matching
gg=svm-grid-ch
case "$gg" in
*grid*) echo $gg ;;
esac
# REGEXP
if echo "$gg" | grep '^....grid*' >/dev/null ; then echo $gg ; fi
if echo "$gg" | grep '....grid*' >/dev/null ; then echo $gg ; fi
if echo "$gg" | grep 's...grid*' >/dev/null ; then echo $gg ; fi
# Extended REGEXP
if echo "$gg" | egrep '(^....grid*|....grid*|s...grid*)' >/dev/null ; then
echo $gg
fi
一些grep
化身还支持-q
(安静)选项作为重定向到/dev/null
的替代方案,但重定向又是最便携的。
【讨论】:
忘记了 egrep 的结束符 ")" 使用grep -q
而不是grep >/dev/null
。以上是关于在 bash 的 if 条件中使用正则表达式的主要内容,如果未能解决你的问题,请参考以下文章