正規表現でグループをキャプチャする必要があります。しかし、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:]]*(.*)"