單引號內的正規表示式 - 失去其價值?

單引號內的正規表示式 - 失去其價值?

我正在閱讀的書 - 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]+'

bashksh93並且zsh有一個專門的運算子用於(擴展)正則表達式匹配。為了在所有三個(以及 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 幾乎相同的正規表示式模式。

相關內容