İki sütundaki değerleri nasıl birleştirebilirim?


11

Aşağıdaki biçimde bir dosya var:

$ cat /tmp/raw
2015-01   5000   1000
2015-02   6000   2000
2015-03   7000   3000

Şimdi, istediğim sonuçların aşağıdaki gibi olması için her satırda 2 ve 3 sütunlarından birleştirilmiş değer elde etmektir:

2015-01   6000
2015-02   8000
2015-03   9000

Bunu denedim ama sadece 2015-03 değeri gibi dosyadaki son değeri gösterir.

Yanıtlar:


11

Kullanmayı deneyebilirsiniz awk:

awk '{ print $1, $2 + $3; }' /tmp/raw

Sonuç olacak (Sanırım 2015-03 değeri 10000 olmalı):

2015-01 6000
2015-02 8000
2015-03 10000

1
Bu kadar çabuk cevap aldığına inanamıyorum: O, başka hiçbir forumda bu kadar hızlı bir cevap alamam :) Teşekkür ederim komut mükemmel çalıştı :)
Syed Jahanzaib

@SyedJahanzaib, Bu cevap sorununuzu çözdüyse, lütfen bir dakikanızı ayırın ve soldaki onay işaretini tıklayarak kabul edin. Bu, soruyu yanıtlandığı gibi işaretler ve Stack Exchange sitelerinde teşekkürlerin ifade edilme şeklidir.
terdon

üzgünüm cevabı işaretlemeyi unuttum. ve orada değerli zaman ve cevaplar için hepinize teşekkür ederim, onlar da bana farklı yöntemlerle hedeflere ulaşmak için öğrenme yardımcı oldu :)
Syed Jahanzaib

@SyedJahanzaib, bu cevap için güzel bir rozet kazandım, ancak terdon'un cevabı daha kesin ve kapsamlı olduğunu düşünüyorum.
taliezin

16

İşte birkaç yol:

  1. Başka bir garip yaklaşım

    awk '{$2+=$3;}NF--' file
    
  2. Perl

    perl -lane 'print "$F[0] ",$F[1]+$F[2]' file
    

    veya

    perl -ape 's/$F[1].*/$F[1]+$F[2]/e' file
    
  3. Kabuk (yukarıdakilerden çok daha yavaş / daha az verimli)

    while read a b c; do echo "$a $((b + c))"; done < file
    

2
$2+=$3daha garip olabilir.
123

@ User112638726 gerçekten öyle. Teşekkürler.
terdon

3
Ayrıca awk '{$2+=$3}NF--'hala boş bir alan 3 asılı değil kullanabilirsiniz . Her ne kadar bu sadece benim tercihim ve kendi başına bir cevap olarak yazı çok benzer :)
123

1
@ User112638726 şimdi bana hiç gelmemişti. Çok daha titiz, teşekkürler!
terdon

Yazdığım bu senin için. Yok nasıl sadece Not sednasılsa anlamaya yönetmek alanları bile tanımlamak için - alanları anında ve alanları içinde w / alanlar - olarak görünüşte böyledir, ancak, Unix regexp'in eşleştirme bütün kavram olduğunu aslında içine bir dize bölünmesine dayanan alanlar bir desene göre ! Kim biliyordu?
mikeserv

5
sed 's/[^ ]* */[&]P/;s//&+pc/3'|dc

... baskılar ...

2015-01   6000
2015-02   8000
2015-03   10000

Bu yüzden bir ilan üzerine düzenli ekspresyonu bir tanımlayan alan ölçüde bir oluşmaktadır *değişken uzunluklu olan karakterlerin tek bir dizi ^olup <boşluk> bir ve hemen ardından *değişken uzunluklu olan karakterlerin tek bir dizi <boşluk> . Bu bildirim, girişte meydana gelen her bir ewline karakteri tarafından sedsınırlanan (varsayılan olarak) bir dize olan ve her biri \niçin yinelenen (varsayılan olarak) bir sonraki ile değiştirilen desen alanına karşı uygulanır .

Bu bildirimin arabirimi iki katlıdır ve her düzeyde, komut sözdiziminin öngörülebilir uygulanmasını sağlamak için en az bir uluslararası IEEE resmi standartlar komitesi tarafından tamamen düzenlenir ve belirtilir sed. Örneğin, sedAPI sözdizimi bu durumda /adres /komutuyla (her zaman herhangi bir sed s///ikame komutunun ilk bileşenidir ) uygulanır , ancak bunun içeriği daha temel bir API tarafından, regcomp()işlevi standart C kütüphanesinde .

Çünkü, güvenle bu ifadeleri yapabilirsiniz sedolan değil daha ziyade, çalıştırılabilir adlı derlenmiştir, sadece bir program, ama sedüzerinde benim Unix benzeri makine bir olan uygulama tarihsel kurulan iyi tanımlanmış bir ve standartlar kontrollü sed uygulama sistemimin düzenlidir- arasında ifade eşleme kütüphaneleri.


Gönderen sedspec:

Tesis sed, XBD Temel Düzenli İfadelerde açıklanan BRE'leri destekleyecektir ...

... bulduğumuz yer ...

Bres ve Eres Hem altında POSIX.1-2008 Sistem Arabirimleri hacmindeki Normal İfade Eşleştirme arayüzü tarafından desteklenir regcomp(), regexec()ve ilgili işlevler.

Aramalar bir uygulama regcomp()bir desen dizesi sunacak ve ...

... [t] regcomp()işlevi, desen argümanı tarafından işaret edilen dizgideki düzenli ifadeyi derleyecek ve sonuçları yapıya yerleştirecektir ...

Buna göre hareket etmek için, söz konusu uygulama daha sonra regcomp()eşlik eden fonksiyona atıfta bulunacaktır ...

... [t] de regexec()işlev ile belirtilen boş sonlandırılmış değeriyle karşılaştırır dize derlenmiş normal ifade ile Süleyman Demirel önceki bir çağrı ile başlatıldı regcomp()...

... regexec()oluşan altdizgelerin uzaklıklar ile [bir] dizinin elemanları dolduracaklardır dize uygun \(parantezli düzenli ifadelerin \)bir desen ... deseni kendisi alt ifadenin bir olarak sayılır ...

... O [t] regexec()bütün doldurmalısınız işlev nmatch unsurları pmatch , nmatch ve pmatch bazı unsurlar bile, uygulama tarafından sağlanmaktadır pmatch içinde subexpressions karşılık gelmez desen .


Ve böylece yaptığımda ...

/[^ ]* */

... sedönce normal ifadeyi derler ve sonuçları hafızaya kaydeder, daha sonra orada saklanan derlenmiş otomatı komutumu yerine getirmek için gerekli olduğu kadar desen alanımın içeriğine uygular. Her seferinde sonuç, döndürülen ofsetlerde sınırlandırılmış bir veya daha fazla boş sınırlandırılmış alan dizisidir regexec().

Ve yaptığımda ...

//

... en son tanımlanmış normal ifadenin kullanılması gerektiğini belirtmek için , önceden derlenmiş düzenli ifadeyi tekrar tekrar sedarayabilir regexec(), ancak muhtemelen bu kez değiştirilen bir dize argümanına uygulayabilir ya da komut olarak yeni nmatch parametrelerini uygulayabilir .

Daha spesifik olarak hala ...

  • s/[^ ]* */[&]P/
    • desen uzayındaki desenin ilk oluşumunu önce [sol köşeli ayraçla, sonra &kendisiyle, ardından ]sağ köşeli ayraçla ve ardından bir Pkarakterle değiştir.
  • s//&+pc/3
    • Geçerli desen uzaya tekrar son kullanılan normal ifade uygulamak ve yerine 3üçüncü oluşumunu deseni ile desen uzayda &kendisi eklenen dize izledi +pc.

Ve böylece her bir sedgirdi girişi için örnek verileriniz göz önüne alındığında stdout'una yazar:

[2015-01   ]P5000   1000+pc
[2015-02   ]P6000   2000+pc
[2015-03   ]P7000   3000+pc

Bu garip görünebilir, ancak dchesap makinesi köşeli parantezler arasındaki girişte dizeleri tırnak içine alır ve Pkomut hem \newline eklemeden yığının üstünü yazdırır hem de daha sonra giriş yığınından çıkarır.

Ve böylece, orada ilk satırı örnek olarak dckullanacağız:

  • [2015-01 ]P
    • Print ve yığının üst pop
  • 5000
    • Numarayı 5000yığının üstüne itin ve o anda yığındaki tüm öğeleri (şimdi yok) birer birer aşağı itin .
  • 1000
    • ancak bu sefer ana yığının üstündeki 5000 sayısı bir aşağı itilir ve yığındaki ikinci öğe olur.
  • +
    • Yığındaki ilk iki sayıyı toplayın, her ikisini de yığının dışına çıkarın ve toplamı yığının üstüne itin.
    • Bu, yalnızca sayıdan oluşan bir yığınla sonuçlanır 6000.
    • Bu, yığındaki en üstteki iki öğeden biri [dize ise sözdizimi hatasıdır ].
  • p
    • pyığının üstünü, ardından yığının \ndışına atmadan ewline ekleyin.
  • c
    • cyığını öğren

Çalıştığına inanıyorum, ama ayrıştıramıyorum. Genel olarak, dc için bir ek ayarlıyorsunuz. İlk kalıp mantıklı. Ben tarih ve sondaki boşluklarla eşleştiğini düşünüyorum, ama bunu karakter sınıfı parantez ([&]) içine koyarak ne elde edemiyorum. Bunu heceleyerek harika olur.
Joe

1
@Joe - daha iyi?
mikeserv

Vaov! Bu çok daha mantıklı (ve bana daha fazla bilgi edinmem gereken bir sürü şey gösteriyor.) Özellikle, mevcut modeli yeniden kullanmak için // kullanımını hiç fark etmemiştim. Gerçek bir örnek alana kadar, okuduğunuz ve unutacağınız şey budur. Çok teşekkürler. Küçük bir komuta ne kadar gücün sığabileceğini ve onu açıklamanın ne kadar sürdüğünü görmek beni güldürdü.
Joe

@Joe - iyi ... belki biraz denize
düştüm
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.