Чи можна замість цього використати 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
Може дати неправильні результати, якщо будь-яке з значень поля чи імен містить рядок "рейтинг", тобто одне з імен сеансу містить слово "рейтинг". Краще:awk -F: '$1 == "rating" {print $2}'
Інгмар Хупп

3
А може awk -F: '/^rating:/ { print $2 }'?
CVn

Я це знаю, але конвертую на основі команди ОП.
кванта

@IngmarHupp Я думав, що саме те саме. Насправді набагато краще відповідати точному запису, що я редагував відповідь із цією зміною. Це, сподіваємось, допоможе людям навчитися ефективніше використовувати awk.
Dan Molding

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

так, ви можете (і повинні) використовувати (one) awk замість (два) grep and 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. Отже, менше циклів лише з однією вилкою + exec, але більше пам’яті та більше IO щоб зняти бінарний диск. Чесно кажучи, я сумніваюся, що будь-який із цих міркувань має значення в сучасних системах, але якщо ви проти мінімізувати, ви йдете!
MadHatter

Foo Bah: дякую за вашу пропозицію щодо редагування, але кванта виступила пізніше, ніж моя, яка є ще більш спрощеною, ніж ваша пропозиція. Я віддав перевагу моєму, оскільки користувачеві 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 має обмежені perms або якщо ви просто любите 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/'

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.