bash スクリプトの正規表現

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 スクリプトでは、 と のみが出力されます$groupsNo match何が問題なのか、誰か教えてもらえますか?

答え1

から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]your を置く必要があります。-[_-]

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

これは、libc のバージョン (egrep または bash のどちらでも) に関係なく動作するはずです。

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

範囲は照合シーケンスに大きく依存するため、移植可能なプログラムでは範囲に依存しないようにする必要があります。

例えば:

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

もちろん、エラーは発生しませんでしたが、期待どおりには動作しません。

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

これは範囲であり、ASCII では、、、、\が含まれます。[^_

答え2

正規表現 (および大きなコード内のバグ) に関する一般的なルール: 段階的に削減して再構築するか、二分法を使用するか、どちらでも自分にとってより効果的な方法を選択してください。

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

関連情報