簡體   English   中英

bash 正則表達式帶引號?

[英]bash regex with quotes?

以下代碼

number=1
if [[ $number =~ [0-9] ]]
then
  echo matched
fi

作品。 但是,如果我嘗試在正則表達式中使用引號,它會停止:

number=1
if [[ $number =~ "[0-9]" ]]
then
  echo matched
fi

我也試過"\[0-9\]" 我錯過了什么?

有趣的是, bash 高級腳本指南建議這應該可行。

Bash 版本 3.2.39。

在 3.1 和 3.2 之間發生了變化。 猜猜高級指南需要更新。

這是自 bash-3.1 發布以來添加到 bash-3.2 的新特性的簡要描述。 與往常一樣,手冊頁 (doc/bash.1) 是查找完整描述的地方。

  1. Bash 中的新功能

剪斷

F。 引用 [[ 命令的 =~ 運算符的字符串參數現在會強制字符串匹配,就像其他模式匹配運算符一樣。

遺憾的是,這將使用腳本破壞現有的引用,除非您有洞察力將模式存儲在變量中並直接使用它們而不是正則表達式。 下面舉例。

$ bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
$ if [[ $number =~ [0-9] ]]; then echo match; fi
match
$ re="[0-9]"
$ if [[ $number =~ $re ]]; then echo MATCH; fi
MATCH

$ bash --version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
match
$ if [[ "$number" =~ [0-9] ]]; then echo match; fi
match

Bash 3.2 引入了一個兼容性選項 compat31,它將 bash 正則表達式引用行為恢復到 3.1

沒有compat31:

$ shopt -u compat31
$ shopt compat31
compat31        off
$ set -x
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ \[0-9] ]]
+ echo no match
no match

使用compat31:

$ shopt -s compat31
+ shopt -s compat31
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ [0-9] ]]
+ echo match
match

補丁鏈接: http : //ftp.gnu.org/gnu/bash/bash-3.2-patches/bash32-039

GNU bash,版本 4.2.25(1)-release (x86_64-pc-linux-gnu)

字符串匹配和正則表達式匹配的一些例子

    $ if [[ 234 =~ "[0-9]" ]]; then echo matches;  fi # string match
    $ 

    $ if [[ 234 =~ [0-9] ]]; then echo matches;  fi # regex natch 
    matches


    $ var="[0-9]"

    $ if [[ 234 =~ $var ]]; then echo matches;  fi # regex match
    matches


    $ if [[ 234 =~ "$var" ]]; then echo matches;  fi # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi   # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # regex match after substituting $var as [0-9]
    matches


    $ if [[ "rss\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work

    $ if [[ "rss\\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work


    $ if [[ "rss'$var'""919" =~ "$var" ]]; then echo matches;  fi # $var is substituted on LHS & RHS and then string match happens 
    matches

    $ if [[ 'rss$var919' =~ "\$var" ]]; then echo matches;  fi # string match !
    matches



    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi # string match failed
    $ 

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match
    matches



    $ echo $var
    [0-9]

    $ 

    $ if [[ abc123def =~ "[0-9]" ]]; then echo matches;  fi

    $ if [[ abc123def =~ [0-9] ]]; then echo matches;  fi
    matches

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match due to single quotes on RHS $var matches $var
    matches


    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # Regex match 
    matches
    $ if [[ 'rss$var' =~ $var ]]; then echo matches;  fi # Above e.g. really is regex match and not string match
    $


    $ if [[ 'rss$var919[0-9]' =~ "$var" ]]; then echo matches;  fi # string match RHS substituted and then matched
    matches

    $ if [[ 'rss$var919' =~ "'$var'" ]]; then echo matches;  fi # trying to string match '$var' fails


    $ if [[ '$var' =~ "'$var'" ]]; then echo matches;  fi # string match still fails as single quotes are omitted on RHS 

    $ if [[ \'$var\' =~ "'$var'" ]]; then echo matches;  fi # this string match works as single quotes are included now on RHS
    matches

正如其他答案中提到的,將正則表達式放在變量中是實現不同版本兼容性的一般方法。 您也可以使用此解決方法來實現相同的目的,同時將正則表達式保留在條件表達式中:

$ number=1
$ if [[ $number =~ $(echo "[0-9]") ]]; then echo matched; fi
matched
$ 

使用局部變量的性能略好於使用命令替換。

對於較大的腳本或 collections 腳本,使用實用程序來防止不需要的局部變量污染代碼並減少冗長可能是有意義的。 這似乎運作良好:

# Bash's built-in regular expression matching requires the regular expression
# to be unqouted (see https://stackoverflow.com/q/218156), which makes it harder
# to use some special characters, e.g., the dollar sign.
# This wrapper works around the issue by using a local variable, which means the
# quotes are not passed on to the regex engine.
regex_match() {
  local string regex
  string="${1?}"
  regex="${2?}"
  # shellcheck disable=SC2046 `regex` is deliberately unquoted, see above.
  [[ "${string}" =~ ${regex} ]]
}

示例用法:

if regex_match "${number}" '[0-9]'; then
  echo matched
fi

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM