Bisakah awk digunakan?

17

Saya ingin mendapatkan nomor ratingsebagai keluaran dari ini

# 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

Saya bisa melakukannya seperti ini

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

tetapi dapat awkdigunakan sebagai gantinya untuk solusi yang lebih sederhana?

Sandra
sumber
Pertanyaan ini tampaknya di luar topik karena ini tentang pemrograman dalam antarmuka Awk dan lebih relevan di StackOverflow.com
Magellan

Jawaban:

32
$ nc localhost 9571 | awk -F: '/rating/ { print $2 }'
kuanta
sumber
7
Dapat memberikan hasil yang salah jika salah satu nilai bidang atau nama berisi string "rating", yaitu salah satu nama sesi memiliki kata "rating" di dalamnya. Lebih baik:awk -F: '$1 == "rating" {print $2}'
Ingmar Hupp
3
Atau mungkin awk -F: '/^rating:/ { print $2 }'?
CVn
Saya tahu itu, tetapi saya mengonversi berdasarkan pada perintah OP.
quanta
@IngmarHupp Saya memikirkan hal yang persis sama. Sebenarnya jauh lebih baik untuk mencocokkan pada catatan yang tepat dalam pertanyaan bahwa saya telah mengedit jawaban dengan perubahan ini. Semoga ini akan membantu orang belajar menggunakan awk lebih efektif.
Dan Moulding
14

Quanta mengalahkan saya untuk itu, tapi saya akan memasukkan sedvarian jika Anda cenderung:

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

Ditto apa yang dikatakan MadHatter. Solusi Anda saat ini sangat baik. (Meskipun saya akan menerima "^rating:"bukan hanya kata untuk memastikan Anda hanya mendapatkan baris yang Anda inginkan.)

SmallClanger
sumber
Saya suka sed! Hal ini sangat kurang dimanfaatkan dan kurang dihargai ...
Mei
9

Anda juga bisa menggunakan shell:

nc localhost 9571 | 
while IFS=: read key val; do [[ $key = "rating" ]] && echo "$val"; done
glenn jackman
sumber
Ini adalah cara tercepat - dan mencegah proses melahirkan apa pun di luar nc. Bagus!
Mei
7

ya, Anda bisa (dan harus) menggunakan (satu) awk alih-alih (dua) grep dan cut:

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

Pastikan untuk mencocokkan baris Anda sebaik yang Anda bisa untuk menghindari bug jelek.

  • /rating/ bekerja,
  • /^rating/ lebih baik (lebih aman),
  • /^rating:/ adalah yang terbaik (dalam hal ini).
Michał Šrajer
sumber
4

Bisa:

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

(Saya tidak tahu apa yang Anda lakukan dengan localhost di atas, jadi gunakan output Anda sebagai input ke perintah awk saya, lalu ganti "cat" dengan "nc ..." - tetapi seharusnya tidak masalah.)

Tetapi mengapa Anda melakukan ini? Cara UNIX adalah memiliki banyak alat kecil, yang masing-masing melakukan satu hal dengan baik, diikat bersama melalui saluran pipa, daripada menggunakan alat multifungsi yang lebih besar. Anda harus memilih satu baris yang cocok, bidang yang dipilih darinya: grepmemilih garis dengan yang cocok, dan cutmemilih bidang dari jalur input; mereka sempurna untuk tugas itu. Tetapi jika Anda benar-benar ingin melakukan semuanya dengan awk, well, begitulah.

MadHatter mendukung Monica
sumber
Salah satu alasannya adalah bahwa menggunakan grepdan cutmembutuhkan pemijahan dua proses, dan menggunakan awk(atau sed) hanya membutuhkan satu. Menghasilkan suatu proses mahal secara komputasi. Juga, tidak seperti menggunakan perlatau ruby(et al), seddan awkjauh lebih ringan di bagian depan.
Mei
2
Cukup adil, meskipun saya perhatikan bahwa ukuran biner awk pada sistem (F15) saya adalah 360.948 byte, sedangkan grep dan cut binary adalah 170824. Jadi lebih sedikit siklus dengan hanya satu fork + exec, tetapi lebih banyak memori, dan lebih banyak IO untuk mendapatkan biner dari disk. Jujur, saya ragu bahwa semua pertimbangan ini penting pada sistem modern, tetapi jika Anda berpikir untuk meminimalkan, itu dia!
MadHatter mendukung Monica
Foo Bah: terima kasih untuk proposal edit Anda, tetapi quanta membuat posting lebih baru dari milik saya yang bahkan lebih ramping daripada saran Anda. Saya lebih suka milik saya karena lebih mudah bagi pengguna awk level pemula untuk melihat cara kerjanya, dan karenanya menolak hasil edit Anda. Terima kasih atas pemikirannya!
MadHatter mendukung Monica
3

Sementara jawaban quanta adalah yang termudah dan yang akan saya tulis juga, saya yakin Anda tidak tahu GNU awk (gawk) dapat melakukan networking juga ? Anda dapat menulis semuanya dengan awk jika Anda benar-benar ingin:

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

Ini mungkin berguna jika server tidak menginstal nc, nc memiliki perms terbatas, atau jika Anda benar-benar suka awk.

Mark McKinstry
sumber
Oooh. Bagus. Contoh jaringan dan coprocessing.
Dr. Edward Morbius
0

Anda juga dapat menggunakan sed,

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

Ini akan memastikan bahwa "peringkat" memulai garis, dan angka itu mengikuti rating:

Sirch
sumber
0

Jika Perl adalah opsi:

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

-aautosplits setiap baris ke dalam @Farray
-F:menggunakan :sebagai pemisah bidang, bukan default ruang kosong
/rating/mengembalikan true jika regex ditemukan
$F[1]adalah elemen ke-2 dari @Farray.
Perl array dimulai dengan elemen 0, sedangkan awk dimulai dengan $ 1

Chris Koknat
sumber