Todas as outras soluções aqui provavelmente falharão em algumas entradas de log, por exemplo. aqueles com espaços dentro do campo de referência ou aspas extras e barras invertidas, nomes de domínio de maiúsculas, https em vez de http, ou palavras-chave dentro do campo de localização, bem como o campo de referência.
Por exemplo:
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"
Para lidar com isso, primeiro precisamos extrair adequadamente o segundo campo com aspas duplas . Observe que os arquivos de log do Apache usam barras invertidas para evitar citações extras ou outros caracteres especiais. Isso significa que expressões regulares ingênuas como "[^"]*"
não são boas o suficiente.
Usando o grep para extrair o campo de referência (segundo campo de aspas duplas):
grep -oP '^[^"]+"[^"\]*(?:\.[^"\]*)*"[^"]+"\K[^"\]*(?:\.[^"\]*)*(?=")' logfile.txt
Parece loucura! Vamos dividir:
- O argumento
o
para grep
significa que acabamos de obter a parte correspondente da linha, não o restante dela
- O argumento
P
para grep
diz para usar expressões regulares compatíveis com Perl
- A estrutura geral da expressão regular em uso aqui,
...\K...(?=...)
, significa que estamos verificando o padrão inteiro, mas apenas as coisas entre o \K
e o (?=...)
serão produzidas
Quebrar ainda mais a expressão regular:
-
^[^"]+
- Obtenha tudo entre o início da linha e o primeiro "
-
"[^"\]*(?:\.[^"\]*)*"
- obtém toda a primeira cadeia entre aspas duplas. Veja esta resposta link
-
[^"]+
- obtém tudo entre as duas strings
-
"\K[^"\]*(?:\.[^"\]*)*(?=")
O mesmo que acima, mas temos o \K
após o primeiro "
para iniciar os dados correspondentes depois disso e o (?=")
para parar os dados correspondentes antes do último "
.
Após este ponto, os dados serão muito mais fáceis de processar, porque você não precisa mais se preocupar com as aspas e extrair o campo corretamente do arquivo de log.
Por exemplo, você pode enviar a saída para outro grep:
grep -oP ... logfile.txt | grep -oPi '^https?://www\.google\.com/search\?\K.*'
Aqui, a opção i
para o segundo grep não faz distinção entre maiúsculas e minúsculas.
Como alternativa, você pode adicionar a verificação do início do google.com
referrer diretamente na primeira expressão regular e mover \K
conforme apropriado, mas eu recomendaria isso, pois é melhor executar duas expressões regulares que ambos fazem um trabalho e fazem bem do que combiná-los em um, onde o seu trabalho não é claro.
Observe que, se você quiser coletar referências de outros domínios do Google, precisará modificar sua expressão regular um pouco. O Google possui muitos domínios de pesquisa .
Se você não se importasse de pegar potencialmente alguns sites que não são do Google, poderia fazer:
... | grep -oPi '^https?://(www\.)?google\.[a-z]{2,3}(\.[a-z]{2})?/search\?\K.*'
Caso contrário, você precisará tentar corresponder apenas aos domínios de pesquisa de propriedade do Google, que é um alvo em constante movimento:
... | 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.*'
Além disso, observe se você deseja incluir a pesquisa de imagens do Google e outros subdomínios de pesquisa, você precisará alterar o (www\.)?
em um dos comandos grep acima para algo como ((www|images|other|sub|domains)\.)?
.