单引号内的正则表达式 - 失去其价值?

单引号内的正则表达式 - 失去其价值?

我正在阅读的书 - Learning the Bash Shell by O'Reilly 指定了一些代码如下:

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

这使用grep搜索实用程序来测试是否$1匹配适当的模式。为此,我们^-[0-9][0-9]*$向 grep 提供正则表达式,该表达式被解释为“一个初始破折号后跟一个数字,可以选择后跟一个或多个数字”。如果找到匹配,grep则将返回匹配,并且测试将为 true,否则grep将不返回任何内容,并且处理将传递给elif测试。

请注意,我们已将正则表达式括在单引号中,以阻止 shell 解释 $ 和 *,并将它们不加修改地传递给 grep。

那么,为什么正则表达式不会'^-[0-9]'像单引号中那样失去其含义,通常单引号内的所有内容都会失去其含义。

感谢您的帮助。

答案1

虽然其他人已经回答了您的具体问题,但我会补充一点

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

检查字符串是否与正则表达式匹配的错误方法有以下几个原因:

  1. 不能用于echo任意数据
  2. 像上面那样将参数扩展保留为不带引号的$1是 split+glob 运算符。
  3. grep不将正则表达式与其完整输入相匹配,而是在其输入的每一行上进行匹配。例如,它会返回 true foo\n-0\nbar
  4. 正则表达式可以匹配零长度,因此在一般情况下检查是否grep产生一些输出是错误的(请注意,命令替换会删除尾随换行符)。最好使用并依赖, 而不是 的grep -q退出状态,并且还可以避免命令替换。grep[
  5. 请注意,该grep命令可以简化为grep -xE '-[0-9]+'

bashksh93zsh有一个专门的运算符用于(扩展)正则表达式匹配。为了在所有三个(以及 bash-3.1)中可移植且可靠地使用它,语法是:

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yash并且zsh还支持:

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

进行字符串(基本)正则表达式匹配的标准命令是expr

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

请注意,^(但不是$)隐含在 中expr。我们还使用该前导空格字符来避免$1恰巧是expr运算符的值出现问题。

另请注意,如果正则表达式包含\(...\),它将影响 的行为expr

总而言之,最好使用awk另一种标准/可移植的方法来实现这一点(注意awk使用扩展的正则表达式):

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

或者使用一个函数:

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

在这种情况下,您还可以使用标准case构造来实现它:

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

要使用grep,您可以将其与--null选项(如果受支持,因为这不是标准选项)一起使用,以告诉它处理 NUL 分隔记录而不是换行分隔记录。由于在大多数 shell 中,$1不能包含 NUL,因此应该是安全的:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

答案2

单引号告诉 shell 按原样保留括起来的字符,没有任何解释。带引号的字符串按原样传递给grep,不带引号:当grep查找其参数时,它会看到

grep

^-[0-9][0-9]*$

并据此采取行动。 (读程序如何运行如果您对 Linux 中的参数构造感到好奇。)

bash并且grep是不同的。此命令使用引号的方式确保bash不会处理该字符串,但grep会处理该字符串。

答案3

单引号可以防止通配(让bash像这样解释通配符*)和通过使用变量扩展$。基本上你是说bash“从字面上获取这些字符并将它们传递给grep”。当grep看到它们时,它是为了理解正则表达式而构建的,所以然后正则表达式在内部解释grep

较短版本:单引号参数提供了一种在参数传递给命令之前逃避 shell 处理的方法。

答案4

它确实失去了意义。grep使用与 bash 几乎相同的正则表达式模式。

相关内容