Использование grep для получения следующего слова после совпадения в каждой строке

Я хочу получить "GET" запросы из журналов моего сервера.

например, это журнал сервера

1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:32:27] code 404, message File not fo$
1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:32:27] "GET /hello HTTP/1.1" 404 -   
1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:41:57] code 404, message File not fo$
1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:41:57] "GET /ss HTTP/1.1" 404 -

когда я пытаюсь с простым grep или awk,

Adi:~ adi$ awk '/GET/, /HTTP/' serverlogs.txt

выдает

1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:32:27] "GET /hello HTTP/1.1" 404 -
1.0.0.127.in-addr.arpa - - [10/Jun/2012 15:41:57] "GET /ss HTTP/1.1" 404 -

Я просто хочу, чтобы отобразить : привет и ss

есть ли способ сделать это?

6 ответов


предполагая, что у вас есть gnu grep, вы можете использовать регулярное выражение в стиле perl для позитивного поиска:

grep -oP '(?<=GET\s/)\w+' file

если у вас нет gnu grep, то я бы посоветовал просто использовать sed:

sed -n '/^.*GET[[:space:]]\{1,\}\/\([-_[:alnum:]]\{1,\}\).*$/s///p' file

если у вас есть gnu sed, это может быть значительно упрощено:

sed -n '/^.*GET\s\+\/\(\w\+\).*$/s///p' file

суть здесь в том, что вам, конечно, не нужны трубы для этого. grep или sed одного будет достаточно.


в этом случае, поскольку файл журнала имеет известную структуру, один из вариантов-использовать cut чтобы вытащить 7-й столбец (поля по умолчанию обозначаются вкладками).

grep GET log.txt | cut -f 7 

используйте трубу, если вы используете grep:

grep -o /he.* log.txt | grep -o [^/].*
grep -o /ss log.txt | grep -o [^/].*

[^ / ] означает извлечение букв после символа ^ из вывода grep


Я пытался сделать это, и наткнулся на эту ссылку: https://www.unix.com/shell-programming-and-scripting/153101-print-next-word-after-found-pattern.html

резюме: используйте grep для поиска совпадающих строк, затем используйте awk для поиска шаблона и печати следующего поля:

grep pattern logfile | \
  awk '{for(i=1; i<=NF; i++) if($i~/pattern/) print $(i+1)}'

Если вы хотите знать уникальные вхождения:

grep pattern logfile | \
  awk '{for(i=1; i<=NF; i++) if($i~/pattern/) print $(i+1)}' | \
  sort | \
  uniq -c

часто проще использовать конвейер, а не одно сложное регулярное выражение. Это работает на данных, которые вы предоставили:

fgrep GET /tmp/foo | 
    egrep -o 'GET (.*) HTTP' |
    sed -r 's/^GET \/(.+) HTTP//'

этот конвейер возвращает следующие результаты:

hello
ss

есть, конечно, другие способы выполнить работу, но это явно работает на предоставленном корпусе.


gawk '{match(,/\/(\w+)/,a);} length(a[1]){print a[1]}' log.txt
hello
ss

если у вас gawk затем выше команда будет использовать match функция для выбора желаемого значения с помощью regex и сохранения его в массив a.