sed komutunu kullanarak linux'daki her satırın son kelimesini yazdırabilir miyiz?


9

varsayalım, eğer aşağıdaki satırlardan oluşan bir dosya varsa,

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

Çıktı şöyle görünmelidir:

66

y6y46y

y5y

y66uyuyy

y46y6y

Komut sed 's/.* //g'dosya adını ve diğer birkaç komutu denedim sed, ancak çalışmıyor.

Tam sedkomutun ne olduğunu bilebilir miyim ?


Kullanmak şart sedmı?
coffeMug

Yanıtlar:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

Bu yine de her boş satır için boş bir satır yazdırır. Bundan kaçınmak için:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

Tek sentezleme alternatif: sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
jimmij

@jimmij - son boş olmayan sıra da ilkse ve ondan önce boşluk yoksa bu çalışmaz. Ayrıca, sadece .*kuyrukta da yapabilirsiniz, muhtemelen - zaten w / boşlukları dışında bir şey ekarte .*[^[:blank:]].
mikeserv


4

Deneyebilirsin :

  • sed 's/.* //'
  • awk '{print $NF}'

4

Neredeyse bitti. Sadece son kelimeyi belirtin:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

Bu ne yapar:

  1. '^. *' satır başındaki ve boşluklardaki her şeyi siler.
  2. '\ (...) \' bir kalıpla eşleşir ve \ 1 olarak döndürür.
  3. '[^]' içinde boşluk olmayan herhangi bir şeyle eşleşir.

(Daha iyi bir çözüm eklemek için düzenlendi. Teşekkürler Hildred!)


1
Daha kısa bir ifade: sed -r 's/.* ([^ ]+)/\1/g'genişletilmiş düzenli ifadelere izin verilirse, genellikle durum budur.
mkalkov

Daha kısa bir sürüm, saklamak istemediklerinizin yerine tutmak istemediklerinizin yerini alarak:sed 's/.* //'
Uriel

2

Örneğin , grepyerine yeterli bir desen kullanabilirsiniz sed:

grep -o "[a-Z0-9]*$"

Bu örnekte, [...]bir "kelime" için uygun kabul edilen karakter aralıkları içerir (bu durumda alfanümerikler, bazıları kaçması gereken başka semboller eklenebilir).


3
Bu, satırın sonunda boşluk olmadığını varsayar. a-Zçünkü menzil ASCII tabanlı yerlerde bile pek mantıklı değil. Bunun -obir GNU uzantısı olduğunu unutmayın .
Stéphane Chazelas

0

Hak kazanırsanız kelimeyi anlamında 1 veya daha fazla boş olmayan herhangi bir karakter dizisiyle ardından Cevap evet kesinlikle olduğunu ve çok sade bir şekilde de yapılır. Bunun nedeni, [[:blank:]]*ve [^[:blank:]]*boolean tamamlayıcılarıdır ve - bir dizedeki tüm karakterlerin eksiksiz olması şartıyla - [[:blank:]]*U [^[:blank:]]*olası tüm dizeleri de aynı şekilde tanımlayabilir .*.

Bir dize içinde eksik bir karakter veya başka bir şekilde geçersiz bayt dizisi varsa, dizeyi doğru bir şekilde kuyruktan başa doğru tanımlayamazlar - bazen bir dizeyi yanlış kodlamada yorumlarken ortaya çıkabilir. Herhangi bir dizede bayt başına tam bir karakter sağlamak için, C yerel ayarı aşağıdaki gibi zorlanabilir:

LC_ALL=C sed ...

... dizeyi baştan sona kuyruk gibi her şey dahil bir desenle tanımlayan sorunları önler .*veya([ ]*[^ ]*)*

Tamamen tamamlayıcı bir desen, desende herhangi bir kopma olmadan mümkün olan en son meydana gelmek için herhangi bir ipin uzunluğunu soldan sağa gerektiği kadar tekrarlayabilir. Bu, kesinlikle, normal bir dildir.

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

Bu sürümlerin her ikisi de hala boş satırlar basacaktır ve bunun nedeni Kleene *yıldızının bir desenin sıfır veya daha fazla örneğiyle eşleşmesidir. Önce sıfır veya daha fazla boş olmayan karakterle, ardından sıfır veya daha fazla boş karakterle eşleşir, ardından gruplanmış dizenin tümüyle eşleşinceye kadar sıfır veya daha fazla eşleşmesi eşleşir.

Tüm bunlarla eşleştikten sonra sihir, yedekte gerçekleşir - gruplar tarafından döndürülen referanslar \1ve \2her birinin son oluşumlarıdır. Bu nedenle, değiştirme yapıldığında tüm dize, sıfır veya daha fazla boş karakter olmayan bir satırda veya alt grupta yalnızca son tekrarlama ile değiştirilir \2.

Tabii ki bu, olası boş bir dize - hatta boş bir dizgi - için çalışır, bu da her iki formun da yalnızca boş karakterler içeren veya hiç boş olmayan satırlar için yeni satır karakterleri yazdıracağı anlamına gelir. Bunu yapmak için yapabileceğiniz birkaç şey var, ama önce karakter sınıfını yazmayı biraz daha kolaylaştıralım:

b='[:blank:]'

Şimdi, yalnızca bir satır boş olmayan bir veya daha fazla karakter içeriyorsa yazdırmak için şunları yapabilirsiniz:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. BRE durumu - değiştirme her zaman gerçekleştirilir ve yalnızca en az bir karakter kalan desen boşlukları yazdırılır.
  2. ERE durumu - yerine koyma, yalnızca en az bir boş karakter içermeyen bir desen alanında denenir.

Her iki form da sözdizimi doğru olduğu sürece her iki yöntemle de çalışır.

-nDesen alanı anahtarı devre dışı bırakır baskı otomatik ve pkarşı bayrak s///ubstitution veya /adres /komutları sonuçları yalnızca başarılı yazdırır.

Aynı mantık, aşağıdaki gibi herhangi bir {num}olayı elde etmek için de uygulanabilir :

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... numher iki normal ifadede de yalnızca {num}boş olmayan karakterlerden oluşan bir dizinin yalnızca belirtilen örneğini basmak için bir sayıyla değiştirilebilir . Burada, dizenin önde gelen alanı için sayının eğri olmamasını sağlamak için biraz farklı bir form kullanılır.

-EERE anahtarının sed, henüz POSIX standart sözdizimi olmasa da, hem BSD hem de GNU sürümlerinde desteklendiğini unutmayın .


Güzel açıklamalar, güzel kesmek, ancak geleneksel sed uygulamalarla (Solaris / usr / bin / sed gibi) işe yaramayacağını ve daha basit bir yaklaşımdan (25 karakterden daha uzun giriş satırları ile hafızayı tüketir) daha pahalı olacağını unutmayın. ya sed_su3Heirloom araç testinden). Yani, cevabı beğenmeme rağmen, bu yaklaşımı önermem.
Stéphane Chazelas

FreeBSD'de de çalışmıyor gibi görünüyor.
Stéphane Chazelas

@ StéphaneChazelas - evet, performans böyle bir şey için gerçekten korkunç, ancak numaralı olayları seçmek için çok etkili olabilir. Ve bir satır sonu için durum s/.* \([^[:blank:]]\{1,\}\).*/\1/çok daha iyidir, ancak birden fazla satır olduğunda daha zordur. Ancak geçen gün bunu 's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]etkili bir şekilde ortaya çıkarabildiğimi keşfettim . Her neyse, mantıkta göz kamaştırıcı bir hata olmadığı sürece mutlu olurum - sadece bir şeyleri kaçırmış olduğumu düşündüm.
mikeserv

@ StéphaneChazelas - oh ve eski seds hakkında - bu biraz garip - standarda göre sağlam olmalı. xrat diyor ... desteklenen ortak tarihi davranışı kabul standart geliştiriciler, "\n*"ancak "\n\{min,max\}", "\(...\)*", ya "\(...\)\{min,max\}"belli bir uygulama olmayan kasıtlı sonucu olarak, onlar subexpressions ve arka referanslar aşağıdaki hem tekrarını ve aralık ifadelerine destekledi.
mikeserv

@ StéphaneChazelas - Ve standart diyor ki ... Geri referansın referans verdiği alt ifade, yıldız ( '*' )veya aralık ifadesi nedeniyle birden fazla dizeyle eşleşiyorsa (bkz. Madde (5)), geri referans son (en sağdaki) ile eşleşmelidir ) bu dizelerin. Bu w / minisedolsa da test eminim - kesinlikle w / minisedgeçen gün garip bir şey test ediyordu , neyse.
mikeserv

0
sed 's/^ star.star //'  filename  or sed 's/^[[:blank:]]star.star[[:blank:]]//' filename

Analiz:

  • s -- vekil

  • / - aranacak ifadenin başlangıcı

  • ^ - satırın başından

  • [[:blank:]]* - satırın başında boşluklar varsa

  • .* - herhangi bir karakter

  • [[:blank:]] - ve boş bir karakter

  • / - ikame edilecek ifadenin başlangıcı

  • / - komut sözdiziminin sonu

PS: Komutanda yıldız yazdım.


Bu, soruda verilen verilere nasıl uygulanır?
Kusalananda

@Scott s/.*[[:blank:]]//, bir satırın sonunda boşluklar olmadığı sürece çalışır.
Kusalananda

-1

Evet. Aşağıdaki sed komutu önce tüm boşluk alanlarını ( s/ *$//) ve ardından son boşluk ( s/.* //) dahil olmak üzere her şeyi kaldırır . [[:blank:]]Sekmeleri ve diğer boşluk benzeri karakterleri yakalamak için büyük olasılıkla boşlukların yerini almaya değer .

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

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.