正規表現と変数を使用したAND条件

正規表現と変数を使用したAND条件

ファイルから読み取った行に、変数に格納されている単語を含む特定の開始と終了があるかどうかをテストしたいと思います。以下はいくつかのコードです。

入力ファイルは次のとおりです。

line one
#; line two
#; line three blah
line four

失敗する最小スクリプトは次のとおりです。

declare ENDOFLINE= "blah"
exec 3< "inputfile"

while read LINE <&3
do
    if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE%$}") )) ]]; 
    then
    echo score!
    else echo no score
    fi
done

しかし、これを行うと:

if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "blah$") )) ]];

正しい行(=>#;3行目など)が正常に識別されました。つまり、行の先頭が "#;" で行の終わりが $ENDOFLINE 変数に含まれる文字列である場合、最初のテストを実行する複合テスト条件が必要です。

助けてくれてありがとう。

答え1

単純な間違いのように見えます。${ENDOFLINE%$}最後からaを削除しましたが、必要なのは文字通り使用し、その後にaを付けて行の終わりをマークすることです。$$ENDOFLINE$ENDOFLINE$

if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE}$") )) ]];

これはzshでは機能しますが、kshまたはbashでは機能しません。 Bashでは正規表現を$引用符で囲む必要があり(そうでない場合は文字通り解釈します)、kshは内部に二重括弧があることを好きではありません[[ … ]](算術命令として解釈します)。この単純なコード行は、3つのシェルすべてで動作します(変数の拡張を必要としない数少ない場所の1つ[[…]]です)。"…"

if [[ $LINE =~ ^"#;" && $LINE =~ $ENDOFLINE$ ]];

$ENDOFLINEと重複しない場合#;(たとえば、ENDOFLINE受け入れる;foo#;;foo拒否する#;foo)、これを単一のテストに減らすことができます。

if [[ $LINE =~ ^"#;".*$ENDOFLINE$ ]];

ここでは、正規表現の代わりにワイルドカードパターンを使用することもできます。

if [[ $LINE = "#;"*"$ENDOFLINE" ]];

この[[…]]構成はすべてのシェルには存在せず、bash、ksh、zsh に固有のものです。他のシェル(Bourne、dash、POSIX)では、ワイルドカードの一致には次の設定を使用できますcase

case $LINE in
  "#;"*"$ENDOFLINE") echo score;;
  *) echo no score;;
esac

答え2

grepを使用してこれを行うこともできます。

end=blah
while read line; do
    if grep -Eq "^#;.*$end$" <<< "$line"; then
        echo score!
    else
        echo no score
    fi
done

(これはbashにあります。他のシェルでは構文が多少異なる場合がありますが、原則は同じです。)

関連情報