次の形式の多くのログエントリを含むサーバーログファイルがあります。
193.1.172.46 - - [23/Mar/2008:03:57:38 +0000] "GET /robots.txt HTTP/1.0" 404 289 "-" "gsa-crawler (Enterprise; M2-N7RQ5RABCA2JT; [email protected],[email protected])"
Google検索エンジンを使用してすべてのアイテムを識別し、そのアイテムからクエリ文字列を取得し、出力にクエリ文字列のみを表示するように求められました。
したがって、grepコマンドを使用して、次のように検索エンジンにアクセスするすべてのエントリを識別しました。
grep "http://www.google.com/search?" logs.txt
これにより、次の項目のリストが表示されます。
143.183.121.3 - - [23/Mar/2008:00:16:59 +0000] "GET /staff/jcarthy/home/2ndYearUnix/usefulcommands2col.pdf HTTP/1.0" 200 78866 "http://www.google.com/search?hl=en&q=frequently+used+unix+aliases&btnG=Google+Search"; "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)"
これで、アイテムのみを表示するリストのhl=en&q=frequently+used+unix+aliases&btnG=Google+Search部分のみを表示するにはどうすればよいですか?
答え1
他のすべての回避策は、参照フィールド内のスペースや追加の引用符、バックスラッシュ、大文字のドメイン名、httpの代わりにhttpsまたは参照フィールド内の場所フィールド、キーワードなどの特定のログエントリで失敗する可能性があります。
たとえば、
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /a b/ HTTP/1.0" 200 0 "http://www.google.com/search?..." "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /i/love/http://www.google.com/search?ing HTTP/1.0" 200 0 "http://www.google.com/search?..." "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET / HTTP/1.0" 200 0 "http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /nohttpver" 200 0 "http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /" 200 0 "http://example.org/http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /" 200 0 "http://WWW.GOOGLE.COM/search?spaces in referrer" "Mozilla/4.0"
これらの問題を解決するため、まず、2番目の二重引用符フィールドを正しく抽出する必要があります。。 Apacheログファイルはバックスラッシュを使用して追加の引用符やその他の特殊文字をエスケープします。これは、単純な正規表現(たとえば)だけでは十分では"[^"]*"
ないことを意味します。
grepを使用して、引用符付きフィールド(二重引用符で囲まれた2番目のフィールド)を抽出します。
grep -oP '^[^"]+"[^"\\]*(?:\\.[^"\\]*)*"[^"]+"\K[^"\\]*(?:\\.[^"\\]*)*(?=")' logfile.txt
クレイジーだと思います!分析してみましょう。
- この主張は、私たちが行の残りの部分ではなく一致する部分だけを得ることを
o
意味します。grep
- 引数はPerl準拠の正規表現を使用するように指示
P
します。grep
- ここで使用される正規表現の全体構造は、全体の
...\K...(?=...)
パターンを確認しますが、\K
との間にあるものだけを出力するという意味です。(?=...)
正規表現をさらに分析すると、次のようになります。
^[^"]+
- 行の先頭と最初の行の間のすべてを取得します。"
"[^"\\]*(?:\\.[^"\\]*)*"
- 二重引用符で囲まれた最初の文字列全体を取得します。この答えを見てくださいhttps://stackoverflow.com/a/5696141/1764245[^"]+
- 2つの文字列の間のすべてを取得します。"\K[^"\\]*(?:\\.[^"\\]*)*(?=")
上記と同じですが、\K
最初の後に"
データの一致を開始し、(?=")
最後の前のデータの一致を停止します"
。
その後、引用符を気にする必要がなくなり、ログファイルからフィールドを正しく抽出する必要がなくなり、データ操作が簡単になります。
たとえば、出力を別のgrepにパイプすることができます。
grep -oP ... logfile.txt | grep -oPi '^https?://www\.google\.com/search\?\K.*'
ここで、i
2番目のgrepオプションは大文字と小文字を区別しません。
google.com
あるいは、最初の正規表現に直接リファラーを起動するためのチェックを追加して必要\K
に応じて移動することもできますが、2つの正規表現を実行すると、1つのタスクを実行して1つに統合するよりも優れたパフォーマンスが得られるため、これに反対することをお勧めします。責任が不明な場所。
他のGoogleドメインからリファラーを収集するには、正規表現を少し変更する必要があります。 Googleが所有多くの検索フィールド。
Google以外のサイトを見つける可能性がある場合は、次のようにします。
... | grep -oPi '^https?://(www\.)?google\.[a-z]{2,3}(\.[a-z]{2})?/search\?\K.*'
それ以外の場合は、移動先のGoogleが所有する検索ドメインのみを一致させようとする必要があります。
... | grep -oPi '^https?://(www\.)?google\.(a[cdelmstz]|b[aefgijsty]|cat|c[acdfghilmnvz]|co\.(ao|bw|c[kr]|i[dln]|jp|k[er]|ls|m[az]|nz|t[hz]|u[gkz]|v[ei]|z[amw])|com(\.(a[fgiru]|b[dhnorz]|c[ouy]|do|e[cgt]|fj|g[hit]|hk|jm|k[hw]|l[bcy]|m[mtxy]|n[afgip]|om|p[aeghkry]|qa|s[abglv]|t[jrw]|u[ay]|v[cn]))?|d[ejkmz]|e[es]|f[imr]|g[aefglmpry]|h[nrtu]|i[emoqst]|j[eo]|k[giz]|l[aiktuv]|m[degklnsuvw]|n[eloru]|p[lnst]|r[osuw]|s[cehikmnort]|t[dgklmnot]|us|v[gu]|ws)/search\?\K.*'
また、Googleの画像検索やその他の検索サブドメインを含めるには、(www\.)?
上記のgrepコマンドのいずれかをに変更する必要があります((www|images|other|sub|domains)\.)?
。
答え2
一般バージョン
awk '$11 ~ /?/ { printf "%s\n",substr($11,1+index($11,"?")) ;}'
どこ
$11 ~ /\?/
お探しですか? URLからsubstr($11,1+index($11,"?")
それ以降の部分を検索してみますか?- パラメータは解析されません。
- これはURLを超えていません(たとえば、とマークされていますspace)
%20
。
以前のバージョン
awk '$11 ~ /http:\/\/www.google.com\/search?/ { print substr($11,26) ;}'
どこ
$11
保持する推奨フィールドの数。調整が必要な場合があります。28
長さは「http://www.google.com/search? 」
答え3
これはかなり読みやすいsedメソッドです。
$ cat log.txt | grep "http://www.google.com/search?" | sed s/^.*search?// | sed s/\"\;.*//
つまり
行の先頭を削除します。
s/ # replace a match which is:
^ # from the start of the line
.* # any number of any characters
search? # the text "search?"
// # with nothing (remove it)
次に、行の終わりを削除します。
s/ # replace a match which is:
\" # a double quote (escaped with backslash)
\; # a semicolon (escaped with backslash)
.* # any number of characters
// # with nothing (remove it)
パラメータのみを残す
答え4
awk -F"[?|;]" '/google.com\/search/{print $2}' log.txt
awk -F? '/google.com\/search/{gsub(";.*","",$2);print $2}' log.txt