Kembalikan hanya sebagian dari garis setelah pola yang cocok


109

Jadi menarik membuka file dengan catdan kemudian menggunakan grepuntuk mendapatkan baris yang cocok hanya membuat saya sejauh ini ketika saya bekerja dengan set log tertentu yang saya hadapi. Ini membutuhkan cara untuk mencocokkan garis ke suatu pola, tetapi hanya untuk mengembalikan bagian garis setelah pertandingan. Bagian sebelum dan sesudah pertandingan akan bervariasi secara konsisten. Saya telah bermain dengan menggunakan sedatau awk, tetapi belum dapat menemukan cara untuk memfilter garis untuk menghapus bagian sebelum pertandingan, atau hanya mengembalikan bagian setelah pertandingan, apakah akan bekerja. Ini adalah contoh baris yang perlu saya filter:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

Bagian yang saya butuhkan adalah segalanya setelah "macet".

Latar belakang di balik ini adalah saya bisa mengetahui seberapa sering sesuatu berhenti:

cat messages | grep stalled | wc -l

Yang perlu saya lakukan adalah mencari tahu berapa kali simpul tertentu terhenti (ditunjukkan oleh bagian sebelum masing-masing titik dua setelah "terhenti". Jika saya hanya memahami untuk itu (yaitu 20 :) mungkin akan mengembalikan garis yang telah gagal lunak, tetapi tidak ada warung, yang tidak membantu saya. Saya hanya perlu memfilter bagian yang macet sehingga saya kemudian dapat mencari simpul tertentu dari yang sudah macet.

Untuk semua maksud dan tujuan, ini adalah sistem freebsd dengan utilitas inti GNU standar, tetapi saya tidak dapat menginstal apa pun tambahan untuk membantu.


@Gilles, Aneh bagaimana itu tidak muncul ketika saya mencari, meskipun saya tidak menggunakan judul saya akhirnya pergi dengan ... tapi itu tidak muncul di layar di bawah judul saya. Lagipula, di samping itu, itu mungkin bisa membawaku ke tempat yang aku inginkan, meskipun aku membutuhkan seluruh kalimat setelah pertandingan, bukan kata pertama - tetapi mungkin tidak banyak berubah.
MaQleod

Judulnya payah. Saya mencuri milikmu yang sangat bagus. Ambil sedsolusinya dan jangan perlakukan whitespace secara khusus.
Gilles

@ Gilles, itu adalah sesuatu yang saya tidak sepenuhnya yakin bagaimana melakukannya. Saya masih belajar sed.
MaQleod


1
@ shaa0601 Saya tidak mengerti pertanyaan Anda, sangat sulit untuk mengikuti komentar tanpa pemformatan. Ajukan pertanyaan baru yang mandiri.
Gilles

Jawaban:


141

Alat kanonik untuk itu adalah sed.

sed -n -e 's/^.*stalled: //p'

Penjelasan detail:

  • -n artinya tidak mencetak apa pun secara default.
  • -e diikuti oleh perintah sed.
  • s adalah perintah penggantian pola.
  • Ekspresi reguler ^.*stalled:cocok dengan pola yang Anda cari, ditambah teks sebelumnya ( .*artinya teks apa pun, dengan inisial yang ^mengatakan bahwa kecocokan dimulai pada awal baris). Perhatikan bahwa jika stalled:terjadi beberapa kali di telepon, ini akan cocok dengan kejadian terakhir.
  • Kecocokan, yaitu semua yang ada di baris hingga stalled:, digantikan oleh string kosong (yaitu dihapus).
  • Yang terakhir pberarti mencetak garis yang diubah.

Jika Anda ingin mempertahankan bagian yang cocok, gunakan referensi-ulang: \1di bagian pengganti menunjukkan apa yang ada di dalam grup \(…\)dalam pola. Di sini, Anda dapat menulis stalled:lagi di bagian pengganti; fitur ini berguna ketika pola yang Anda cari lebih umum daripada string sederhana.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Terkadang Anda ingin menghapus bagian dari garis setelah pertandingan. Anda dapat memasukkannya dalam pertandingan dengan memasukkan .*$di akhir pola (teks apa pun .*diikuti pada akhir baris $). Kecuali jika Anda menempatkan bagian itu dalam grup yang Anda referensi di teks pengganti, akhir baris tidak akan berada di output.

Sebagai ilustrasi lebih lanjut tentang grup dan referensi, perintah ini menukar bagian sebelum pertandingan dan bagian setelah pertandingan.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

Saya sudah mencoba dua contoh pertama dan sepertinya menggantung. Saya tidak mendapatkan pesan kesalahan, saya juga tidak mendapatkan prompt baru, tidak ada apa-apa.
MaQleod

2
@ MaQleod Oh, menunggu input pada input standar, yang di sini adalah terminal karena Anda belum mengarahkannya. Di sini Anda akan melakukan pengalihan input sed … <messages, karena Anda ingin memproses data dari file. Untuk bertindak atas data yang dihasilkan oleh perintah lain, Anda akan menggunakan pipa: somecommand | sed ….
Gilles

1
benar, pemadaman akhir hari di sana. Perintah bekerja dengan sempurna, terima kasih.
MaQleod

1
Penjelasan sed terbaik yang pernah saya lihat sejauh ini - terima kasih!
Jon Wadsworth

1
@ungalcrys Versi lebih pendek dari apa? Ini tidak setara dengan salah satu perintah dalam jawaban saya. Saya sarankan menulis sed 's/^.*stalled//'karena -rini khusus untuk Linux dan tidak bekerja pada sistem lain seperti macOS dan di sini Anda tidak mendapatkan manfaat apa pun dari itu.
Gilles

72

Alat kanonik lain yang sudah Anda gunakan grep::

Sebagai contoh:

grep -o 'stalled.*'

Memiliki hasil yang sama dengan opsi kedua Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

The -obendera mengembalikan --only-matchingbagian dari ekspresi, sehingga tidak seluruh baris yang - tentu saja - yang biasanya dilakukan oleh grep.

Untuk menghapus "terhenti:" dari output, kita dapat menggunakan alat kanonik ketiga, potong:

grep -o 'stalled.*' | cut -f2- -d:

The cutperintah menggunakan pembatas :dan mencetak lapangan 2 sampai akhir. Ini masalah preferensi tentu saja, tetapi cutsintaks yang saya temukan sangat mudah diingat.


1
Terima kasih telah menyebutkan -oopsi! Saya ingin menunjukkan bahwa greptidak mengenalinya \nsebagai baris baru, jadi contoh pertama Anda hanya cocok dengan nkarakter pertama . Misalnya, echo "Hello Anne" | grep -o 'A[^\n]*'mengembalikan string A. Namun, echo "Hello Anne" | grep -o 'A.*'mengembalikan yang diharapkan Anne, karena .cocok dengan karakter apa pun kecuali baris baru.
adamlamar

1
Perhatikan bahwa kutipan di sekitar cutpembatas -d':'dihapus oleh @poige. Saya merasa lebih mudah diingat dengan kutipan, misalnya dengan -d' 'atau -d';'.
Anne van Rossum

Menurut temuan Anda, lebih mudah untuk mengingat untuk menggunakan kutipan -f 2juga. Serius, kenapa tidak?
poige

Karena pembatas seperti semi-colon ;daripada colon :akan diartikan berbeda jika tidak dikutip. Tentu saja itu perilaku logis, tapi tetap saja saya suka mengandalkan memori otot. Saya tidak suka mengutip pembatas satu kali tetapi tidak pada waktu yang lain. Hanya preferensi pribadi, seperti yang saya katakan sebelumnya: lebih mudah diingat.
Anne van Rossum

periode yang merupakan bagian dari yang .*diperlukan, bekerja dengan baik untuk saya: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' pengembalianxyz text
ron

4

Saya biasa ifconfig | grep eth0 | cut -f3- -d:mengambil ini

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

dan membuatnya terlihat seperti ini

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
Apakah ini menjawab pertanyaan?
Stephen Rauch

1
Anda dapat menggunakan cat /sys/class/net/*/address, tidak perlu parsing.
Anne van Rossum

1

Namun alat kanonik lain yang Anda pertimbangkan awkdapat digunakan dengan baris berikut:

awk -F"stalled" '/stalled/{print $2}' messages

Penjelasan detail:

  • -Fmendefinisikan pemisah untuk garis, yaitu, "terhenti". Semuanya sebelum pemisah ditangani $1dan semuanya setelah dengan $2.
  • /reg-ex/ Menelusuri persamaan reguler yang cocok, dalam hal ini "terhenti".
  • {print $<n>}- mencetak n kolom. Karena pemisah Anda didefinisikan sebagai macet, segala sesuatu setelah macet dianggap sebagai kolom kedua.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.