sed: yalnızca eşleşen grubu yazdır


133

Son iki sayıyı (bir int, bir kayan nokta; ardından isteğe bağlı boşluk) alıp yalnızca yazdırmak istiyorum.

Misal:

foo bar <foo> bla 1 2 3.4

Yazdırmalı:

2 3.4

Şimdiye kadar aşağıdakilere sahibim:

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

bana verecek

foo bar <foo> bla 1 replacement

Ancak, bunu 1. grupla değiştirmeye çalışırsam, tüm satır yazdırılır.

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

Satırın yalnızca gruptaki normal ifade ile eşleşen bölümünü nasıl yazdırabilirim?

Yanıtlar:


138

Tüm satırı eşleştirin, bu nedenle .*normal ifadenizin başına bir ekleyin . Bu, tüm satırın grubun içeriğiyle değiştirilmesine neden olur

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
-rVeya "--regexp-extended" seçeneğini eklemek zorunda kaldım, aksi takdirde invalid reference \1 on s "command's RHS" hatasını alıyordum .
Daniel Sokolowski

15
@DanielSokolowski Sana kullanırsanız o hatayı alıyorum düşünüyorum (ve )yerine \(ve \).
Daniel Darabos

3
.*Ayıklamak istediğiniz dize her zaman satırın sonunda değilse, normal ifadenin sonuna eklemeyi unutmayın .
Teemu Leisti

3
Bu benim için işe yaramayacak çünkü .*açgözlü ve açgözlü değil.*?
sondra.kinsey

@DanielDarabos Sadece bunu belirtin (ve )ubuntu 16.04'te hata yaratmayacaktır. Bu yüzden bu yorumun modası geçmiş olduğunu düşünüyorum.
Li haonan

72

grep , ayıklamak için doğru araçtır.

örneğinizi ve normal ifadenizi kullanarak:

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

12
tüm grup için harika, ancak bireysel gruplar için sed gerekli
jozxyqk

grep -o msysgit çalıştıran sistemlerde bağlantı sağlamaz, ancak sed yapar.
cchamberlain

Bunu grep ile çözmek için ileriye bakma ve arkaya bakma kullanan bir yanıt için @jozxyqk ile bağlantılı soruya bakın.
Joachim Breitner

Yönlendirmeli grep -oaramalar içeren bir modelden bir grubu çıkarabilirsiniz . stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

Ve başka bir seçenek için, awk ile giderdim!

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

Bu, girişi (burada STDIN kullanıyorum, ancak girişiniz kolayca bir dosya olabilir) boşluklara böler ve ardından son-bir-bir alanı ve sonra son alanı yazdırır. $NFDeğişkenler alan sayısı boşluk üzerinde patlayan sonra bulundu tutun.

Bunun yararı, son iki alandan önce gelen şeyin değişip değişmediğinin önemli olmamasıdır, sadece son ikisini istediğiniz sürece çalışmaya devam edecektir.


3

Kes komutu tam bu durum için tasarlanmıştır. Herhangi bir sınırlayıcı üzerinde "keser" ve sonra hangi parçaların çıktılacağını belirleyebilirsiniz.

Örneğin: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Şu çıktıyla sonuçlanacak: 2 3.4

-d sınırlayıcıyı ayarlar

-f, çıktılanacak 'alanlar' aralığını seçer, bu durumda, orijinal dizginin 6'dan 7'ye kadar olan parçalarıdır. Aralığı gibi bir liste olarak da belirtebilirsiniz 6,7.


Yalnızca belirli sütunları yazdırmak içinawk '{ print $2" "$6 }'
nurettin

@nurettin Bence yorumunuz garip cevaplardan biri için yapılmış olabilir.
carlin.scott

Bu sayfayı ziyaret ettiğimde kesmeyi denedim ve sınırlamalarını fark ettim ve bu yazının kalitesini artırmak için yorum yapmak yerine awk'de daha genelleştirilmiş bir sürüm yazmaya karar verdim.
nurettin

1
Evet, bence bu, awk ile ilgili farklı bir cevaba ait. Yazdıklarınızı yapmak için kesme komutu:cut -d " " -f 2,6
carlin.scott

Ah, bunu bilmiyordum, sadece aralık verebileceğini düşünmüştüm. Bunun için teşekkürler.
nurettin

2

@Kent'in bunun için çok uygun olduğuna katılıyorum grep -o. Bir desen içindeki bir grubu çıkarmanız gerekirse, bunu 2. bir grep ile yapabilirsiniz.

# 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.