bash正規表現はすべてのグループを認識しません

bash正規表現はすべてのグループを認識しません

正規表現でグループをキャプチャする必要があります。しかし、BASH_REMATCHいくつかのグループを取得できないため、bash変数の概念を理解していないようです。これは私のコードです。

# I want to get the values around the first '=' if it exists
inp="short =  some word  long = span desc=sth to ' be ' described value=45"
regex="\s*(\w*)\s*=\s*(.*)"

if [[ $inp =~ $regex ]]; then 
  echo; 
  echo -e "input: \"$inp\""; 
  echo -e "regex: \"$regex\"";   
  echo "matching groups: ${#BASH_REMATCH[*]}"; 
  for i in $(seq 0 $(( ${#BASH_REMATCH[*]}-1 ))); do 
    echo -e "$i: \"${BASH_REMATCH[$i]}\""; 
  done; 
fi

input: "short =  some word  long = span desc=sth to ' be ' described value=45"
regex: "\s*(\w*)\s*=\s*(.*)"
matching groups: 3
0: "=  some word  long = span desc=sth to ' be ' described value=45"
1: ""
2: "  some word  long = span desc=sth to ' be ' described value=45"

私は最初のグループが「短い」と予想しました。なぜ認識されないのですか? regex101.comで正規表現をテストすると、グループ1は「短い」と表示されます。リンクは次のとおりです。 https://regex101.com/r/oZGQS6/1


編集1

最初のグループはsedを使用して識別されます(グループ化された角かっこを除いて同じ正規表現を使用しました)。

$ sed 's/\s*\(\w*\)\s*=\s*\(.*\)/\1\n\2/' <<< $inp
short
some word  long = span desc=sth to ' be ' described value=45

編集2

提案どおりにアンカーを正規表現に入れようとしましたが、今回は結果が認識されませんでした。

regex="^\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)$"
regex="^\s*(\w+)\s*=\s*(.*)$"

これらの正規表現は機能せず、まったく結果が得られません。

文字列の16進値を確認しました。

$ od -vAn -tx1c <<<"$inp"
           73  68  6f  72  74  20  3d  20  20  73  6f  6d  65  20  77  6f
           s   h   o   r   t       =           s   o   m   e       w   o
           72  64  20  20  6c  6f  6e  67  20  3d  20  73  70  61  6e  20
           r   d           l   o   n   g       =       s   p   a   n    
           64  65  73  63  3d  73  74  68  20  74  6f  20  27  20  62  65
           d   e   s   c   =   s   t   h       t   o       '       b   e
           20  27  20  64  65  73  63  72  69  62  65  64  20  76  61  6c
               '       d   e   s   c   r   i   b   e   d       v   a   l
           75  65  3d  34  35  0a                                        
           u   e   =   4   5  \n 

変なキャラクターじゃないみたいです。

ちなみに、私はMacでbash v 4.4.0を使用しています。

$ bash --version
GNU bash, version 4.4.0(1)-release (x86_64-apple-darwin15.6.0)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

編集3

何か新しいもの。 bash v.4.1.2を使用してLinuxシステムでこれを試してみましたが、結果は良くありませんでした。

$ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

3 つの正規表現がすべて有効です。

regex="\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)$"
regex="^\s*(\w+)\s*=\s*(.*)$"

結果は次のとおりです。

input: "short =  some word  long = span desc=sth to ' be ' described value=45"
regex: "^\s*(\w*)\s*=\s*(.*)"
matching groups: 3
0: "short =  some word  long = span desc=sth to ' be ' described value=45"
1: "short"
2: "some word  long = span desc=sth to ' be ' described value=45"

これがまさに私が期待したものです。しかし、なぜ私のMacでは動作しませんか? Bashのバージョンが更新されました。私はすべての最新バージョンのbashで動作するソリューションが欲しいです。

答え1

Bashの正規表現は固定されていません。これは、文字列のどの場所でも一致できることを意味します。これは正規表現エンジンによって異なります。ここでは、一致は図のように等号で始まりますBASH_REMATCH[0]

^回避策:文字列の先頭にaを追加してくださいregex

[更新]上記のようにbash正規表現エンジン(man 3 regex)を使用してください。これはプラットフォームによって異なる場合があります。正規表現に問題がある場合は、\letterショートカットを避け、Posixに対応するものを使用してください。

regex="^\s*(\w*)\s*=\s*(.*)"
たとえば、regex="^[[:space:]]*([_[:alnum:]]*)[[:space:]]*=[[:space:]]*(.*)"

関連情報