Можно ли вместо этого использовать awk?


17

Я хотел бы получить номер в ratingкачестве вывода из этого

# nc localhost 9571 
language:
language:en_ZA.UTF-8
language:en_ZW.UTF-8
session-with-name:Ubuntu Classic (No effects):gnome-session --session=2d-gnome
session-with-name:Ubuntu (Safe Mode):gnome-session -f --session=2d-gnome
session-with-name:Ubuntu Classic:gnome-session --session=classic-gnome
xsession:/etc/X11/Xsession
rating:94

Я могу сделать это так

# nc localhost 9571 | grep rating | cut -d: -f2
94

но можно было awkбы использовать вместо этого для более простого решения?


Этот вопрос, кажется, не по теме, потому что он касается программирования в интерфейсе Awk и более актуален на StackOverflow.com
Magellan

Ответы:


32
$ nc localhost 9571 | awk -F: '/rating/ { print $2 }'

7
Может давать неверные результаты, если какое-либо из значений или имен поля содержит строку «rating», т.е. в одном из имен сеанса есть слово «rating». Лучше:awk -F: '$1 == "rating" {print $2}'
Ингмар Хапп

3
Или может быть awk -F: '/^rating:/ { print $2 }'?
CVn

Я знаю это, но я конвертирую на основе команды ОП.
кванты

@IngmarHupp Я думал точно так же. На самом деле, гораздо точнее сопоставить с конкретной записью, что я отредактировал ответ с этим изменением. Надеемся, что это поможет людям научиться использовать awk более эффективно.
Дэн Молдинг

14

Кванта опередил меня, но я включу sedвариант, если вы склонны так:

nc localhost 9571 | sed -ne 's/^rating://p'

То же самое сказал и MadHatter. Ваше текущее решение отлично звучит. (Хотя я предпочел бы "^rating:"не просто слово, чтобы убедиться, что вы получите только ту строку, которую хотите.)


Я люблю sed! Он так недооценен и недооценен ...
Мэй,

9

Вы также можете просто использовать оболочку:

nc localhost 9571 | 
while IFS=: read key val; do [[ $key = "rating" ]] && echo "$val"; done

Это самый быстрый способ - и предотвращает порождение любых процессов за его пределами nc. Ницца!
Мэй

7

да, вы можете (и должны) использовать (один) awk вместо (двух) grep и cut:

$ nc localhost 9571 | awk -F: '/^rating:/ { print $2 }'

Будьте уверены, чтобы соответствовать вашей линии как можно лучше, чтобы избежать уродливых ошибок.

  • /rating/ работает,
  • /^rating/ лучше (безопаснее),
  • /^rating:/ лучше всего (в этом случае).

4

Он может:

nc localhost 9571  | awk -F: '{ if ($1 == "rating") print $2 }' 

(Я не знаю, что вы делаете с localhost выше, поэтому использовал ваш вывод в качестве входных данных для моей команды awk, а затем заменил «cat» на «nc ...» - но это должно быть хорошо.)

Но зачем ты это делаешь? Способ UNIX состоит в том, чтобы иметь множество небольших инструментов, каждый из которых хорошо выполняет свою задачу, соединенных вместе с помощью конвейеров, а не с помощью более крупных многофункциональных инструментов. Вам нужно выбрать одну совпадающую строку, выбрать из нее одно поле: grepвыбрать строки с совпадениями и cutвыбрать поля из входных строк; они идеально подходят для этой задачи. Но если вы действительно хотите сделать это все в одном с помощью awk, ну, вот и все.


Одна из причин заключается в том, что для использования grepи cutтребуется порождение двух процессов, а для использования awk(или sed) требуется только один. Создание процесса является вычислительно дорогим. Кроме того, в отличие от использования perlили ruby(и др.), sedИ awkгораздо более легкий фронт.
Мэй

2
Вполне справедливо, хотя я отмечаю, что размер двоичного файла awk в моей системе (F15) составляет 360948 байт, в то время как двоичные файлы grep и cut вместе составляют 170824. Таким образом, меньше циклов только с одним fork + exec, но больше памяти и больше IO чтобы получить двоичный файл с диска. Честно говоря, я сомневаюсь, что любое из этих соображений имеет значение для современных систем, но если вы склонны к минимизации, то вы идете!
MadHatter

Фу Бах: спасибо за ваше предложение по редактированию, но Quanta сделал пост позже, чем мой, что еще более упорядочено, чем ваше предложение. Я предпочел мой, потому что пользователю awk начального уровня легче увидеть, как он работает, и поэтому отклонил ваше редактирование. Спасибо за мысль, хотя!
MadHatter,

3

Хотя ответ Кванты самый простой и тот, который я бы написал тоже, держу пари, вы не знали, что GNU awk (gawk) тоже может работать в сети ? Вы можете написать все это с помощью awk, если вы действительно хотите:

BEGIN {
    FS = ":"
    f = "/inet/tcp/0/127.0.0.1/9571"
    while ((f |& getline) > 0)
        if ($1 ~ /^rating$/) {print $2}
}

Это может быть полезно, если на сервере не установлен nc, nc имеет ограниченные привилегии или если вам действительно нравится awk.


Оооо. Ницца. Сеть и пример сопроцессинга.
Доктор Эдвард Морбиус

0

Вы также можете использовать Sed,

nc localhost 9571 | sed -n "s/^rating:\([\d]*\)/\1/p"

Это будет гарантировать, что «рейтинг» начинает строку, и что цифры следуют за rating:


0

Если Perl вариант:

nc localhost 9571 | perl -F: -lane 'print $F[1] if /rating/'

-aавтоматическое разбиение каждой строки в @Fмассиве
-F:используется :в качестве разделителя полей, вместо значения по умолчанию пробела
/rating/возвращает значение true, если найдено регулярное выражение,
$F[1]являющееся вторым элементом @Fмассива.
Массивы Perl начинаются с элемента 0, тогда как awk начинается с $ 1

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.