1. ホーム
  2. regex

[解決済み] Bashのif文での正規表現マッチング

2022-08-17 22:29:21

質問

何がいけなかったのでしょうか?

スペース、小文字、大文字、数字を含むすべての文字列にマッチしようとしました。特殊文字もいいですが、特定の文字をエスケープする必要があると思います。

TEST="THIS is a TEST title with some numbers 12345 and special char *&^%$#"

if [[ "$TEST" =~ [^a-zA-Z0-9\ ] ]]; then BLAH; fi

これは明らかに、大文字、小文字、数字、スペースをテストするだけです。しかし、うまくいきません。

* UPDATE *

もっと具体的に説明するべきだったようです。以下は、実際の実際のコード行です。

if [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; fi

* UPDATE *

./anm.sh: line 265: syntax error in conditional expression
./anm.sh: line 265: syntax error near `&*#]'
./anm.sh: line 265: `  if [[ ! "$TITLE" =~ [a-zA-Z0-9 $%^\&*#] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; return; fi'

どのように解決するのですか?

bashの [[ ]] の構築について知っておくべき重要なことがいくつかあります。一つ目は

の間の単語に対して単語分割とパス名展開が行われません。 [[]] ;チルダ展開、パラメータ展開、変数展開、算術展開、コマンド置換、プロセス置換、引用符除去が行われます。

2つ目のことです。

<ブロッククオート

追加の二項演算子 '=~' が利用できます。... 演算子の右側の文字列は拡張正規表現とみなされ、それに応じてマッチングされます... パターンのどの部分でも、文字列としてマッチさせるために引用することができます。 .

結果的に $v の両側で =~ はその変数の値に展開されますが、その結果は単語分割やパス名展開されません。言い換えれば、左側で変数の展開を引用しないままにしても全く問題ありませんが、右側で変数の展開が起こることを知っておく必要があります。

というわけで、もしあなたが書いたら [[ $x =~ [$0-9a-zA-Z] ]] と書くと $0 の内部は正規表現が解釈される前に展開されてしまうので、おそらく正規表現のコンパイルに失敗します。 $0 の展開が数字やAscii値が1桁未満の区切り記号で終わっていない限り)。 のように右辺を引用する場合は、次のようになります。 [[ $x =~ "[$0-9a-zA-Z]" ]] のように引用すると、右辺は正規表現ではなく、普通の文字列として扱われます。 (そして $0 はまだ展開されます)。この場合、本当に必要なのは [[ $x =~ [\$0-9a-zA-Z] ]]

の間の表現も同様に [[]] は正規表現が解釈される前に単語に分割されます。そのため、正規表現中のスペースはエスケープするか引用符で囲む必要があります。もし文字、数字、スペースにマッチさせたいなら、次のようにします。 [[ $x =~ [0-9a-zA-Z\ ] ]] . その他の文字も同様に、次のようにエスケープする必要があります。 # のようにエスケープする必要がある。もちろん、パターンを変数に入れることもできます。

pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...

bash のレキサを通過するためにエスケープや引用が必要な文字を多く含む正規表現では、多くの人がこのスタイルを好みます。しかし、注意: この場合 はできません。 という変数展開の引用ができません。

# This doesn't work:
if [[ $x =~ "$pat" ]]; then ...

最後に、あなたがやろうとしていることは、変数が有効な文字だけを含んでいるかどうかを確認することだと思います。このチェックを行う最も簡単な方法は、無効な文字が含まれていないことを確認することです。つまり、次のような式です。

valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...

! は、テストを否定して "一致しない" 演算子に変え、さらに [^...] 以外の任意の文字を意味します。 ... を意味します。

パラメータ展開と正規表現演算子の組み合わせにより、bashの正規表現構文は"ほとんど読みやすい"になりますが、まだいくつかのゴチャゴチャがあります。(いつもそうでしょうか?)ひとつは、あなたが ]$valid であっても $valid が引用されていたとしても、一番最初を除いては、です。(これはPosixの正規表現のルールです。 ] を文字クラスに含めたい場合は、先頭に書く必要があります。 - は最初にも最後にも書くことができるので、もし両方の ]- で始まる必要があります。 ] で終わり、さらに - となり、正規表現 "I know what I'm doing" の顔文字が表示されるようになります。 [][-] )