'Kes' ile son alan nasıl bulunur


310

Olmadan kullanarak sedya awk, sadece cut alanların sayısı her satırı ile bilinmeyen veya değiştirmek olduğunda, nasıl son alanı alabilirim?


8
cutKomuta aşık mısın :)? neden başka Linux komutları olmasın?
Jayesh Bhoi

7
Olmadan sedveya awk: perl -pe 's/^.+\s+([^\s]+)$/$1/'.
jordanm


4
@MestreLion Çoğu kez insanlar bir sorunun varyasyonuna bir çözüm bulmak için bir soru okurlar. Bu, cutdesteklemediği bir şeyi destekleyen yanlış önermeyle başlar . Ancak, okuyucunun takip etmesi daha kolay olan kodu düşünmeye zorlaması açısından yararlı olduğunu düşündüm. Ben kullanım için hızlı, kolay bir yol istedi cutiçin birden sözdizimi kullanmaya gerek kalmadan awk, grep, sedvb revşey hile yaptı; çok zarif ve hiç düşünmediğim bir şey (diğer durumlar için tıknaz olsa bile). Diğer cevaplardan diğer yaklaşımları da okumayı sevdim.
Beejor

3
Buraya gerçek bir sorun geldi: Bir .gitattributes dosyasını güncellemek için kaynak ağaçtaki tüm farklı dosya uzantılarını bulmak istiyorum. Yani find | cut -d. -f<last>doğal eğim olduğunu
studog

Yanıtlar:


679

Böyle bir şey deneyebilirsiniz:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev

açıklama

  • rev "maps.google.com" ifadesini tersine çevirir moc.elgoog.spam
  • cut sınırlayıcı olarak nokta (yani '.') kullanır ve ilk alanı seçer; moc
  • son olarak, almak için tekrar ters çeviriyoruz com

6
Sadece kullanmak değil cutama sedya da olmadan. awkOP ne düşünüyor?
Jayesh Bhoi

7
@tom OP, son birkaç saat içinde bundan daha fazla soru sordu. OP ile etkileşimlerimize dayanarak awk / sed / etc olduğunu biliyoruz. ödevlerinde izin verilmiyor, ancak rev'e atıfta bulunulmadı. Yani
denemeye

4
@zfus anlıyorum. revDaha sonra başka bir şey yapıştırmak isteyebilir .
tom

17
çift revbüyük ideal!
Ford Guo

6
Müthiş, basit, mükemmel, açıklama için teşekkürler - uzun adımlarla borulu komutların her adımını açıklayan yeterli kişi yok
Pete

128

Bir parametre genişletmesi kullanın. Bu çok daha verimli herhangi harici komuta tür daha cut(ya da grepdahil).

data=foo,bar,baz,qux
last=${data##*,}

Bash'deki yerel dize manipülasyonuna giriş için bkz. BashFAQ # 100 .


3
@ErwinWessels: Çünkü bash gerçekten yavaş. Verileri toplu olarak işlememek için değil, boru hatlarını çalıştırmak için bash kullanın. Yani, zaten kabuk değişkeninde bir metin satırınız varsa veya while IFS= read -ra array_var; do :;done <(cmd)birkaç satırı işlemek istiyorsanız bu harika bir şey . Ancak büyük bir dosya için rev | cut | rev muhtemelen daha hızlıdır! (Ve elbette awk bundan daha hızlı olacaktır.)
Peter Cordes

2
@PeterCordes, awk büyük bir dosya için daha hızlı olacaktır, ancak sabit faktör başlangıç ​​maliyetlerinin üstesinden gelmek için biraz girdi gerekir. (Bu cevapta verilen sözdiziminin geçerli kaldığı, awk'a yakın performansa sahip ksh93 gibi kabuklar da vardır; bash son derece durgun, ancak mevcut tek seçeneğe bile yakın değil).
Charles Duffy

1
Teşekkürler @PeterCordes; Her zamanki gibi her aracın kullanım durumları var sanırım.
Erwin Wessels

1
Bu, bir bashbetik içindeki tek bir değişkeni kesmenin en hızlı ve en kısa yoludur ( zaten bir bashbetik kullandığınızı varsayarsak ). Harici bir şey demeye gerek yok.
Ken Sharp

1
@Balmipour ... Ancak rev olan işte bu sağlar ne olursa olsun OS kullandığınız özgü - tüm UNIX sistemleri arasında standardize değil. Komutlar ve yardımcı programlar hakkındaki POSIX bölümü için bölüm listesine bakın - orada değil. Ve ${var##prefix_pattern}olduğu değil aslında bash-özgü in; İçinde POSIX sh standardı , bu yüzden aksine bölüm 2.6.2 (bağlantılı) sonunu görmeyi revherhangi uyumlu kabuk üzerinde her zaman kullanabilirsiniz.
Charles Duffy

89

Sadece kullanmak mümkün değildir cut. İşte kullanmanın bir yolu grep:

grep -o '[^,]*$'

Diğer ayırıcılar için virgül kullanın.


3
Tam tersini yapmak ve son alan dışında her şeyi bulmak için:grep -o '^.*,'
Ariel

2
revBenim durumuma bir sorun çok baytlı unicode karakterler eklemek çünkü bu özellikle yararlı oldu .
Brice

3
MinGW üzerinde bunu yapmaya çalışıyordum ama benim grep sürümü -o desteklemiyor, bu yüzden sed 's/^.*,//'hangi ve son virgül dahil olmak üzere tüm karakterleri boş bir dize ile değiştiren kullanılır.
TamaMcGlinn

46

Awk olmadan? ... Ama awk ile çok basit:

echo 'maps.google.com' | awk -F. '{print $NF}'

AWK cebinizde olması için daha güçlü bir araçtır. -F alan ayırıcısı için NF alan sayısı ise (son dizini de gösterir)


2
Bu evrenseldir ve her seferinde tam olarak beklendiği gibi çalışır. Bu senaryoda, cutOP'nin nihai çıktısını elde etmek için kullanmak, biftek "kesmek" için bir kaşık kullanmak gibidir (pun amaçlı :)). awkbiftek bıçağıdır.
Hickory420

3
Gereksiz kullanımından kaçının echo, uzun dosyalar için komut dosyasını yavaşlatabilir awk -F. '{print $NF}' <<< 'maps.google.com'.
Anil_M

14

Birden çok yol var. Bunu da kullanabilirsiniz.

echo "Your string here"| tr ' ' '\n' | tail -n1
> here

Açıkçası, tr komutu için boş alan girişi ihtiyacınız olan sınırlayıcı ile değiştirilmelidir.


Teşekkür ederim! busybox sh 1.0.0 çalışan bir şey :) :)
kevinf

1
Bu bana en basit cevap, daha az boru ve daha net bir anlam gibi geliyor
joeButler

1
Bu, OP'nin büyük olasılıkla kastettiği tüm dosya için çalışmaz.
Amir

7

Kesim dışında hiçbir şey kullanmamak için mümkün olan tek çözüm budur:

echo "string" | kes -d '.' -f2- [repeat_following_part_forever_or_until_out_of_memory:] | kes -d '.' -f2-

Bu çözümü kullanarak, alanların sayısı gerçekten bilinmiyor olabilir ve zaman zaman değişebilir. Ancak, satır uzunluğu yeni satır karakteri de dahil olmak üzere LINE_MAX karakterlerini veya alanlarını aşmamalıdır, bu nedenle rastgele bir sayıda alan bu çözümün gerçek koşulu olarak asla kullanılamaz.

Evet, çok aptalca bir çözüm ama bence kriterleri karşılayan tek çözüm.


2
Güzel. Sonuncuyu al. kapalı "dize" ve bu çalışır.
Matt

2
Herkes bir şeyin imkansız olduğunu söylediğinde ve sonra birisi çalışan bir cevapla çaldığında seviyorum. Gerçekten çok aptal olsa bile.
Beejor

cut -f2-Çıktı artık değişmeyene kadar bir döngü içinde yineleme yapılabilir .
loa_in_

4

Giriş dizenizde eğik çizgi yoksa, basenamebir alt kabuk kullanabilirsiniz :

$ basename "$(echo 'maps.google.com' | tr '.' '/')"

Bu kullanılmaz sedveya awkaynı zamanda da kullanılmaz cut, bu yüzden soruna bir cevap olarak nitelendirilip nitelenmediğinden emin değilim.

Eğik çizgi içerebilen giriş dizeleri işlenirse bu işe yaramaz. Bu durum için geçici bir çözüm, eğik çizgiyi geçerli bir giriş dizesinin parçası olmadığını bildiğiniz başka bir karakterle değiştirmek olacaktır. Örneğin, |dosya adlarında pipe ( ) karakterine de izin verilmez, bu nedenle bu işe yarar:

$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'


0

Aşağıdaki gibi bir liste yolu olan filelist.txt adında bir dosyanız varsa: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h

o zaman bunu yapabilirsiniz: rev filelist.txt | kes -d "/" -f1 | devir


0

Bu eski soruya sadece eğlenmek için bir yaklaşım eklemek:

$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info

$ cat tmp.sh # showing off the script to do the job
#!/bin/bash
delim=';'
while read -r line; do  
    while [[ "$line" =~ "$delim" ]]; do
        line=$(cut -d"$delim" -f 2- <<<"$line")
    done
    echo "$line"
done < input.file

$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info

Bash'in yanı sıra sadece kesim kullanılır. Şey, ve yankı, sanırım.


Meh, neden sadece kesimi tamamen kaldırmak ve sadece bash ... x] kullanmak while read -r line; do echo ${line/*;}; done <input.fileaynı sonucu verir.
Kaffe Myers

-1

Sadece sondaki bir sınırlayıcının var olduğundan emin olursak, işe yaradığını fark ettim. Benim durumumda virgül ve boşluk sınırlayıcılarım var. Sonuna bir boşluk ekliyorum;

$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b

Ve ans="a, b, c"üretir bgereksinimlerini karşılamak etmeyen, "alanların sayısı her satırı ile bilinmeyen veya değişimiz" .
jww
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.