シェルは、複数行の文字列の最後の行に指定されたパターンが含まれているかどうかをテストします。

シェルは、複数行の文字列の最後の行に指定されたパターンが含まれているかどうかをテストします。

複数行の文字列が指定されたパターンを含む行で終わっていることを確認したいと思います。

このコードは失敗し、一致しません。

s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match

答え1

bash3.2以降で3.1との互換性が有効になっていない場合(compat31またはオプションを使用BASH_COMPAT=3.1)、引用符付き正規表現演算子(引用符付き演算子(、、、、)\と一緒に使用されない)は特別な意味を排除します。bash'...'"..."$'...'$"..."

[[ $var =~ 'OK$' ]]

OK$リテラルを含む文字列のみ一致($リテラル一致$

[[ $var =~ OK$ ]]

次に終わる文字列と一致しますOK(つまり、$RE演算子は文字列の最後で一致します)。

これは、正規表現または変数に格納されている特定の代替結果にも適用されます。

[[ $var =~ $regexp ]]   # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string

シェル構文にいくつかの文字(たとえば、一致しない場合は空白、、、、括弧)を引用する必要があるため、これは厄介になる可能性があります<。たとえば、正規表現(3文字の後にa、a、またはaが続く)を一致させるには、次のようなものが必要です。>&.{3} <> [)}]&" <> ")}&

[[ $var =~ .{3}" <> "[}\)]\& ]]

どの文字を引用すべきかわからない場合は、いつでも一時変数を使用できます。。これはまた、コードを互換性にするか、次のことを意味しますbash31zshksh93

pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here

compat31これは、(or)オプションを使用せずにシステム正規表現のPOSIX以外の拡張演算子を利用する唯一の方法です。BASH_COMPAT=3.1

たとえば、\<多くの正規表現エンジンでこれを単語境界として扱うには、次のものが必要です。

pattern='\<word\>'
[[ $var =~ $pattern ]]

行為:

[[ $var =~ \<word\> ]]

これをシェル引用演算子としてbash扱い、正規表現ライブラリに渡す前に削除するのと同じようには機能しません。\<word>

ksh93の場合、状況ははるかに悪いです。

[[ $var =~ "x.*$" ]]

たとえば、一致しますがwhatever-xa*一致しませんwhatever-xfoo。上記の引用は特別な意味を削除します*が、.Norの特別な意味は削除しません$

より単純な動作:引用は正規表現演算子(bash31のように)の意味を変更しないので、動作をより予測可能にします(ERE(with)のzsh代わりにPCRE正規表現を使用することもできます)。set -o rematchpcre

yash[[...]]コンストラクタはありませんが、[演算子=~が組み込まれています(にもありますzsh)。もちろん、[通常のコマンドと同様に、引用は正規表現演算子の解釈方法には影響しません。


また、厳密に言えば、$s3行ではなく2行の完全な行と終わらない行が含まれていることに注意してください。それが含まれていますhello\nworld\nOKOK$拡張正規表現では、$演算子は最後の項目のみと一致します。ひも

合計3行ひも、例えばhello\nworld\nOK\n(コマンド置換を使用すると、コマンド置換バーを取得できません)みんな末尾改行)は$後で一致するので\n一致OK$しません。

ただし、にフラグを渡さないため、文字列の末尾と改行文字の前がある場合は一致しますzsh -o pcrematch$PCRE_DOLLAR_ENDONLYpcre_compile通常、シェルの変数には末尾の改行文字は含まれておらず、含まれている場合は通常データとして扱われたいので、これは悪い考えに見えるかもしれません。

答え2

少なくともでは、bashRHSを引用すると文字列比較として扱われます。

$ s=$(printf 'hello\nworld\nOK\n')
$ echo "$s"
hello
world
OK
$ [[ "$s" =~ OK$ ]] && echo "match" || echo "no match"
match

しかし、

$ s=$(printf 'hello\nworld\nOK$\n')
$ echo "$s"
hello
world
OK$
$ [[ "$s" =~ 'OK$' ]] && echo "match" || echo "no match"
match

答え3

よく知られていない事実:caseそれも同じです。

case "$(printf 'hello\nworld\nOK\n')" in
  *$'\nOK') echo "match";;
  *) echo "no match";;
esac

「Cスタイル」文字列$'...'はBash拡張(シェル文字列でバックスラッシュエスケープコードを使用できるコンテキストを提供します\n)ですが、移植性のために次のように言うことができます。

*"
OK") echo "match";;

POSIXと完全に互換性のあるシェルスクリプトを入手してください。

ただし、ステートメントで使用できるパターンは、case適切な正規表現ではなく、シェルグローブパターンです。

関連情報