Если вы не укажете явную опцию -o
, по умолчанию должен быть файл с именем a.out
. На странице руководства по компилятору GNU man gcc
это объясняется следующим образом:
-o file
Place output in file file. This applies to whatever sort of output
is being produced, whether it be an executable file, an object
file, an assembler file or preprocessed C code.
If -o is not specified, the default is to put an executable file in
a.out, the object file for source.suffix in source.o, its assembler
file in source.s, a precompiled header file in source.suffix.gch,
and all preprocessed C source on standard output.
Вот довольно читаемый подход 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)
, оставив только параметры
awk -F"[?|;]" '/google.com\/search/{print $2}' log.txt
awk -F? '/google.com\/search/{gsub(";.*","",$2);print $2}' log.txt
общая версия
awk '$11 ~ /?/ { printf "%s\n",substr($11,1+index($11,"?")) ;}'
где
$11 ~ /\?/
поиск ? в URLsubstr($11,1+index($11,"?")
поиск части после ?%20
)предыдущая версия
awk '$11 ~ /http:\/\/www.google.com\/search?/ { print substr($11,26) ;}'
где
$11
- номер поля, содержащего ссылку, возможно, потребуется корректировка28
- длина "http://www.google.com/search?"Все другие решения здесь, скорее всего, не сработают на некоторых записях журнала, например. те, которые содержат пробелы внутри поля реферера или лишние кавычки и обратную косую черту, имена доменов в верхнем регистре, https вместо http или ключевые слова внутри поля местоположения, а также поля реферера.
Например:
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
означает, что мы просто получаем совпадающую часть строки, а не остальную часть P
аргумент grep
указывает ему использовать Perl-совместимые регулярные выражения ... \ K ... (? = .. .)
означает, что мы проверяем весь шаблон, но будут выведены только вещи между \ K
и (? = ...)
. регулярное выражение вниз:
^ [^ "] +
- Получить все, что находится между началом строки и первым "
"[^" \\] * (?: \\. [^ "\\] *) *"
- Получить всю первую строку в двойных кавычках.См. Этот ответ https://stackoverflow.com/a/5696141/1764245 [^ "] +
- Получите все, что находится между двумя strings "\ 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 | изображения | другие | под | домены) \.)?
.
Думаю, я понял это.
grep "http://www.google.com/search?" logs.txt | cut -d" " -f11 | sed -r 's/^.{30}//'
Кажется ли это приемлемым решением?