다음 형식의 많은 로그 항목이 포함된 서버 로그 파일이 있습니다.
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"
이러한 문제를 해결하기 위해,먼저 두 번째 큰따옴표 필드를 올바르게 추출해야 합니다.. Apache 로그 파일은 백슬래시를 사용하여 추가 따옴표나 기타 특수 문자를 이스케이프 처리합니다. 이는 간단한 정규식(예를 들어)만으로는 "[^"]*"
충분하지 않음을 의미합니다.
grep을 사용하여 인용된 필드(큰따옴표로 묶인 두 번째 필드)를 추출합니다.
grep -oP '^[^"]+"[^"\\]*(?:\\.[^"\\]*)*"[^"]+"\K[^"\\]*(?:\\.[^"\\]*)*(?=")' logfile.txt
미친 것 같아! 분석해 보겠습니다.
- 이 주장은 우리가 줄의 나머지 부분이 아닌 일치하는 부분만 얻는다는
o
것을 의미합니다 .grep
- 인수는 Perl 호환 정규식을 사용하도록
P
지시합니다 .grep
- 여기에 사용된 정규식의 전체 구조는
...\K...(?=...)
전체 패턴을 확인하지만\K
과 사이에 있는 것만 출력한다는 의미입니다.(?=...)
정규식을 더 자세히 분석하면 다음과 같습니다.
^[^"]+
– 줄의 시작 부분과 첫 번째 줄 사이의 모든 것을 가져옵니다."
"[^"\\]*(?:\\.[^"\\]*)*"
– 큰따옴표로 묶인 첫 번째 문자열 전체를 가져옵니다. 이 대답을 봐https://stackoverflow.com/a/5696141/1764245[^"]+
– 두 문자열 사이의 모든 것을 가져옵니다."\K[^"\\]*(?:\\.[^"\\]*)*(?=")
위와 동일하지만\K
첫 번째 이후에"
데이터 일치를 시작하고(?=")
마지막 이전의 데이터 일치를 중지합니다"
.
그 후에는 더 이상 따옴표에 대해 걱정할 필요가 없고 로그 파일에서 필드를 올바르게 추출할 필요가 없으므로 데이터 작업이 더 쉬워집니다.
예를 들어 출력을 다른 grep으로 파이프할 수 있습니다.
grep -oP ... logfile.txt | grep -oPi '^https?://www\.google\.com/search\?\K.*'
여기서 i
두 번째 grep 옵션은 대소문자를 구분하지 않습니다.
google.com
또는 첫 번째 정규식에 직접 리퍼러 시작에 대한 검사를 추가 하고 \K
필요에 따라 이동할 수 있지만 두 정규식을 실행하는 것이 하나의 작업을 수행하고 하나로 통합하는 것보다 더 나은 성능을 발휘하므로 이에 반대하는 것이 좋습니다. 책임이 불분명한 곳.
다른 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