grepが先行する「.」を無視するのはなぜですか?

grepが先行する「.」を無視するのはなぜですか?

ダウンロードしたWebページで文字列を見つけようとしますcurl。私はgrep一致する文字列を見つけるために使用します。正規表現柄。

以下は私が見つけたい文字列です。

./download/file.php?id=86753

この文字列は部分Webページのより大きな文字列は次のとおりです。

href="./download/file.php?id=86753"

私が使用するマントラgrepは次のとおりです。

grep -Eo '\.\/download\/file\.php\?id=[0-9]+' dlfile.html

しかし、見つかりました。何もないhtmlファイルから。ただしgrep、次のように変更すると、2つの一致が生成されます。これ最初のゲーム2つ目は役に立たない障害物なので、含めないでください。

grep -Eo '\/download\/file\.php\?id=[0-9]+' dlfile.html
/download/file.php?id=86753
/download/file.php?id=62517

2番目の(不要な)一致を含む文字列は次のとおりです。

href="https://web.archive.org/web/20190824162104/https://www.somewhere.com/forums/download/file.php?id=62517&sid=907ab04af81e19ad758c5bcf8ebdca32"

.問題は、文字列の先行(ドット)が認識されないようです。これは、必要な文字列と望ましくない文字列の主な違いです。

Q:これがうまくいかないのはなぜですか?何が必要ですか?


私の環境:Debian派生バージョン(Raspberry Pi)、「bullseye」バージョン

私はどちらを使用していますかgrepbash

$ grep --version
grep (GNU grep) 3.6
...
$ bash --version
GNU bash, version 5.1.4(1)-release (arm-unknown-linux-gnueabihf)

答え1

grep -EERE(拡張正規表現)が必要です。ドットは常にリテラルにエスケープする必要があります。疑問符は ERE に有効な演算子なので、リテラルと一致させるにはエスケープする必要があります。

echo 'href="./download/file.php?id=86753"' |
    grep -Eo '\./download/file.php\?id=[0-9]+'

頼む、

grepが先行する「.」を無視するのはなぜですか?

問題は、文字列の前の.(ドット)を認識しないようです。

あなたのパターンは一致し、リテラルポイントが必要です(これは正しい\.意味です)。ただし、質問に記載されている文字列は検索しようとしているWebページには表示されません。grepこれを無視しないでください。望むより:

xmlstarlet format --html BDegguyM 2>/dev/null |
    xmlstarlet select -T -t -v '//a[@class="postlink"]/@href' -n

  https://forums.raspberrypi.com/download/file.php?id=86753
  https://web.archive.org/web/20190824162104/https://www.raspberrypi.org/forums/download/file.php?id=62517&sid=907ab04af81e19ad758c5bcf8ebdca32

私はあなたがこれらの最初のものが欲しいと仮定しているので、それを抽出してみましょう。

xmlstarlet format --html BDegguyM 2>/dev/null |
    xmlstarlet select -T -t -v '//dl[@class="file"]//a[@class="postlink"]/@href' -n

  https://forums.raspberrypi.com/download/file.php?id=86753

次から始まる/download部分だけが欲しいなら

xmlstarlet format --html BDegguyM 2>/dev/null |
    xmlstarlet select -T -t -v '//dl[@class="file"]//a[@class="postlink"]/@href' -n |
    sed -E 's!^https?://[^/]+!!'

  /download/file.php?id=86753

grep操作に適したツールの代わりに実際に使用したい場合は、同じ結果が返されます。

grep -Po 'https?://[^/]+\K/download/file.php\?id=\d+' BDegguyM

  /download/file.php?id=86753

答え2

タイトル行の質問に対する回答:

grepが先行する「.」を無視するのはなぜですか?

簡単に言えば、そうではありません。

1つのファイルに付属の2つのサンプル入力行を使用します。

$ cat dlfile.html
href="./download/file.php?id=86753"
href="https://web.archive.org/web/20190824162104/https://www.somewhere.com/forums/download/file.php?id=62517&sid=907ab04af81e19ad758c5bcf8ebdca32"

■前の不要な(おそらく無害であるがPOSIXに従って定義されていない動作に確実に依存する)バックスラッシュを削除し、質問から/2つのコマンドを実行します。grep

$ grep -Eo '\./download/file\.php\?id=[0-9]+' dlfile.html
./download/file.php?id=86753

$ grep -Eo '/download/file\.php\?id=[0-9]+' dlfile.html
/download/file.php?id=86753
/download/file.php?id=62517

最初のものはgrep先行を含み、先行する入力の文字列.とのみ一致し.、2番目はgrep先行を含まず、.当然aで始まらない入力の2つの文字列と一致します.

grep上記の最初の事項についてのあなたのコメントに関して:

しかし、これはhtmlファイルに何も見つかりません。

それから:

  1. 質問のgrepコマンドが実際に使用するコマンドとは異なります。
  2. 実際のHTMLファイルには、サンプル入力として使用するために提供した文字列は含まれていません。

したがって、コマンドがどのような形であるか、入力がどのような形であるかわからない場合は、一部の入力を解析するコマンドをデバッグするのに役立つために実際にできることはありません。

答え3

ここにはすでに多くのコメントがありました。それらのいくつかは正当な懸念と質問を提起しました。ついに問題が解決したと思い、仕上げのためにここに投稿します。

あなたが収集したように、私は必要な情報項目を含む文字列のURLを「スクレイピング」しています。約2年前、私はこの作業を「自動化」するスクリプトを開発しましたが、それはうまくいきました。このスクリプトは主に次の2つのことを行います。

  1. curlgrepウェブページ
  2. 結果に応じて別のgrep措置を講じてください。

「何か変わった」数日前。私の「信頼できる」スクリプトは、実行されるたびにエラーが発生し始めました。このエラーは、grep文字列が見つからないことを示します。私がgrep使用するもの:

curl blah-blah | grep -o '\.\/download\/file\.php?id.[0-9]*'

今日まで、私は何も変わったことがないことを知りません。変更の1つは、サイトが「CloudFlare」という会社にアウトソーシングされたことです。もう1つは、curlブラウザのダウンロードを処理するのと同じ方法でダウンロードを処理しないようです。もう一つの変化が起きているようです。

私の質問に反映された混乱は、部分的にこれらのサイトの変更によるものです。しかし、それはほとんど私のせいです。。質問を投稿する前に、もっと忍耐力を持って、エラーをより徹底的に調査する必要がありました。関係者全員にお詫び申し上げます。

私がこの経験を通して学んだと主張する一つのことは次のとおりです。grepHTMLを解析するのに適したツールではありません。。共有する参考資料が2つあります。

  1. これ物議を醸すワイヤーSOでHTMLを解析するための正規表現の再利用

  2. これHiks Gerganovの情報投稿タイトルは、「シェルのHTMLタグ間でテキストを抽出するためのHTML解析」です。

答え4

\/一般に変更すると正常に動作します/

#!/usr/bin/sh

printf 'href="%s"\n' \
       './download/file.php?id=86753' \
       'elsewhere/download/file.php?id=86753' |
    grep -oE '\./download/file\.php\?id=[0-9]+'

出力:

./download/file.php?id=86753

望ましくないギリギリな状況をよりよく拒否するために、\B始めと終わりに追加することを検討することもできます。\b

関連情報