web-dev-qa-db-ja.com

bashスクリプトの正規表現

初めてのbashスクリプトなので、たぶん簡単な間違いを犯しています。

基本的に、ユーザーのグループを取得するスクリプトを記述しようとしています。特定のグループに属している場合は、それに応じてログに記録されます。明らかにより多くの機能があるでしょうが、私が正規表現さえも動作させることができないときにそれを構築する意味はありません!

これまでのところ、私はこれを持っています:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

私がその正規表現を試したすべての場所で動作します。しかし、bashスクリプトでは、$groups、 に続く No match。だから誰かがそれの何が悪いのか教えてもらえますか?

12
jrdn

man 7 regexから:

大括弧式は、「[]」で囲まれた文字のリストです。 …

…リテラル「-」を含めるには、最初または最後の文字にします…。 [A] '\'を含む他のすべての特殊文字は、ブラケット式内の特別な意味を失います。

Egrepで正規表現を試行するとエラーが発生します。

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

これは、エラーも発生する単純なバージョンです。

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

\は特別なものではないため、[a-z]と同様に、これは範囲です。 -のように、末尾に[_-]を付ける必要があります。または:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

これは、libcのバージョン(egrepまたはbash)に関係なく機能するはずです。

編集:実際のロケール設定にも依存します。マンページはこれについて警告します:

範囲は照合順序に非常に依存するため、移植可能なプログラムは範囲に依存しないようにする必要があります。

例えば:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

もちろん、エラーは発生しませんでしたが、意図したとおりに動作していません。

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

これは、ASCIIでは\[^、および_を含む範囲です。

13
derobert

正規表現(およびコードの大きな部分にあるバグ)の一般的なルール:それを切り下げて、段階的に再構築するか、二分法を使用します。

この場合、犯人はアンダースコアであることが判明しました-バックスラッシュでエスケープすると機能します。

4
peterph