sed: hanya mencetak grup yang cocok


133

Saya ingin mengambil dua angka terakhir (satu int, satu float; diikuti oleh spasi opsional) dan hanya mencetaknya.

Contoh:

foo bar <foo> bla 1 2 3.4

Harus mencetak:

2 3.4

Sejauh ini, saya memiliki yang berikut:

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

akan memberi saya

foo bar <foo> bla 1 replacement

Namun, jika saya mencoba menggantinya dengan grup 1, seluruh baris dicetak.

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

Bagaimana saya bisa mencetak hanya bagian dari garis yang cocok dengan regex di grup?

Jawaban:


138

Cocokkan seluruh baris, jadi tambahkan a .*di awal regex Anda. Ini menyebabkan seluruh baris diganti dengan konten grup

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

38
Saya harus menambahkan opsi -ratau `--regexp-extended` jika tidak saya mendapatkan invalid reference \1 on error RHS` s's command.
Daniel Sokolowski

15
@ DanielSokolowski Saya pikir Anda mendapatkan kesalahan itu jika Anda menggunakan (dan )bukannya \(dan \).
Daniel Darabos

3
Ingat juga untuk menambahkan .*ke akhir regexp jika string yang ingin Anda ekstrak tidak selalu di akhir baris.
Teemu Leisti

3
Ini tidak akan berhasil bagi saya karena .*serakah dan sed tidak memiliki yang tidak serakah.*?
sondra.kinsey

@DanielDarabos Sebut saja (dan )tidak akan menimbulkan kesalahan di ubuntu 16.04. Jadi saya pikir komentar ini sudah ketinggalan zaman.
Li haonan

72

grep adalah alat yang tepat untuk mengekstraksi.

menggunakan contoh dan regex Anda:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

12
bagus untuk seluruh grup, meskipun sed diperlukan untuk grup individual
jozxyqk

grep -o tidak port pada sistem yang menjalankan msysgit tetapi sed tidak.
cchamberlain

Lihat pertanyaan yang ditautkan oleh @jozxyqk untuk jawaban yang menggunakan lihat-depan dan lihat-belakang untuk menyelesaikan ini dengan grep.
Joachim Breitner

Anda dapat mengekstrak grup dari suatu pola dengan grep -opanggilan telepon. stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

Dan untuk pilihan lain, saya akan pergi dengan awk!

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

Ini akan membagi input (saya menggunakan STDIN di sini, tetapi input Anda dapat dengan mudah menjadi file) pada spasi, dan kemudian mencetak bidang terakhir tapi satu, dan kemudian bidang terakhir. The $NFvariabel memegang sejumlah bidang ditemukan setelah meledak di ruang.

Manfaat dari ini adalah bahwa tidak masalah jika apa yang mendahului dua bidang terakhir berubah, selama Anda hanya ingin dua bidang terakhir itu akan terus berfungsi.


3

Perintah cut dirancang untuk situasi yang tepat ini. Ini akan "memotong" pada pembatas apa pun dan kemudian Anda dapat menentukan potongan mana yang harus di-output.

Misalnya: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Akan menghasilkan output dari: 2 3.4

-d mengatur pembatas

-f memilih rentang 'bidang' ke output, dalam hal ini, ini adalah potongan ke 6 sampai 7 dari string asli. Anda juga dapat menentukan rentang sebagai daftar, seperti 6,7.


Untuk hanya mencetak kolom tertentu, pipa keawk '{ print $2" "$6 }'
nurettin

@nurettin Saya pikir komentar Anda mungkin ditujukan untuk salah satu jawaban awk.
carlin.scott

Saya mencoba memotong ketika saya mengunjungi halaman ini dan menyadari keterbatasannya dan memutuskan untuk menulis versi yang lebih umum dalam awk alih-alih sebagai komentar untuk meningkatkan kualitas posting ini.
nurettin

1
Ya, saya pikir itu milik jawaban berbeda yang melibatkan awk. Perintah cut untuk melakukan apa yang Anda tulis adalah:cut -d " " -f 2,6
carlin.scott

ah, saya tidak tahu itu, saya pikir Anda hanya bisa memberikan rentang. Terima kasih untuk itu.
nurettin

2

Saya setuju dengan @kent bahwa ini cocok untuk grep -o. Jika Anda perlu mengekstrak grup dalam suatu pola, Anda dapat melakukannya dengan grep ke-2.

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9
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.