web-dev-qa-db-ja.com

シェルスクリプト。正規表現を使用して文字列を抽出する方法

シェルスクリプトは初めてです。 curlを使用してhttpリクエストを送信し、正規表現を使用して文字列を抽出したい。たとえば、http応答からドメイン名を抽出するにはどうすればよいですか? (例は学習目的のみです)

#!/bin/bash
name=$(curl google.com | grep "www\..*com")
echo "domain name is"
echo $name
41
ashim

bash正規表現 の使用:

re="http://([^/]+)/"
if [[ $name =~ $re ]]; then echo ${BASH_REMATCH[1]}; fi

Edit-OPは構文の説明を求めました。 正規表現の構文 は、ここでは完全に説明できない大きなトピックですが、例を理解するのに十分な説明を試みます。

re="http://([^/]+)/"

これは、bash変数reに格納されている正規表現です。つまり、入力文字列に一致させるもので、できれば部分文字列を抽出します。分解する:

  • http://は単なる文字列です-正規表現が一致するには、入力文字列にこの部分文字列が含まれている必要があります
  • []通常、角括弧は「角括弧内の任意の文字に一致する」という意味で使用されます。したがって、c[ao]tは「cat」と「cot」の両方に一致します。 ^内の[]文字は、これを修正して、「すべての文字に一致するexcept角括弧内の文字。したがって、この場合[^/] 「/」以外の任意の文字に一致します。
  • 角括弧式は1文字のみに一致します。 +を末尾に追加すると、「1つ以上の先行部分式に一致」と表示されます。したがって、[^/]+は、「/」を除くすべての文字のセットの1つ以上に一致します。
  • 部分式を()かっこで囲むと、その部分式に一致したものを後で処理するために保存することを意味します。使用している言語がこれをサポートしている場合、これらのサブマッチを取得するメカニズムが提供されます。 bashの場合、BASH_REMATCH配列です。
  • 最後に、「/」で完全一致を実行して、完全修飾ドメイン名とそれに続く「/」の最後まで一致するようにします。

次に、入力文字列を正規表現に対してテストして、一致するかどうかを確認する必要があります。これを行うには、bash条件を使用できます。

if [[ $name =~ $re ]]; then
    echo ${BASH_REMATCH[1]}
fi

Bashでは、[[ ]]は拡張条件付き​​テストを指定し、=~ bash正規表現演算子を含めることができます。この場合、入力文字列$nameが正規表現$reと一致するかどうかをテストします。一致する場合、正規表現の構築により、(かっこ()から)サブマッチがあることが保証され、BASH_REMATCH配列を使用してアクセスできます。

  • この配列${BASH_REMATCH[0]}の要素0は、正規表現、つまり「 http://www.google.com/ "」に一致する文字列全体になります。
  • この配列の後続の要素は、後続のサブマッチの結果になります。正規表現内で複数のサブマッチ()を使用できることに注意してください-BASH_REMATCH要素はこれらに順番に対応します。したがって、この場合、${BASH_REMATCH[1]}には「www.google.com」が含まれます。これは、必要な文字列だと思います。

BASH_REMATCH配列の内容は、正規表現=~演算子が最後に使用されたときにのみ適用されることに注意してください。したがって、さらに正規表現の一致を実行する場合、must必要なコンテンツを毎回この配列から保存します。

これは長い説明のように思えるかもしれませんが、正規表現の複雑さのいくつかについて本当に説明しました。それらは非常に強力である可能性があり、まともなパフォーマンスであると信じていますが、正規表現の構文は複雑です。また、正規表現の実装はさまざまであるため、異なる言語は異なる機能をサポートし、構文に微妙な違いがある場合があります。特に、正規表現内の文字のエスケープは、特にそれらの文字が特定の言語で異なる意味を持つ場合、厄介な問題になる可能性があります。


別の行で$re変数を設定し、条件でこの変数を参照する代わりに、正規表現を条件に直接配置できることに注意してください。ただし、 bash 3.2 では、そのようなリテラル正規表現を囲む引用符が必要かどうかに関するルールが変更されました。正規表現を別の変数に入れるのは簡単な方法であるため、=~マッチ演算子をサポートするすべてのbashバージョンで期待どおりに条件が機能します。

90
Digital Trauma

1つの方法はsedを使用することです。例えば:

echo $name | sed -e 's?http://www\.??'

通常、sed正規表現は「/」で区切られますが、「?」を使用できます。 「/」を検索しているため。別のbashトリックがあります。 @DigitalTraumaの答えは、私がそれを提案するべきであることを思い出させた。それは似ています:

echo ${name#http://www.}

(DigitalTraumaは、 "http://"を処理する必要があることを思い出させてくれました。)

7
Mars