İlk sütuna göre satırları awk veya sed ile bitiştir


12

awkAşağıdaki durumda nasıl kullanabilirim ?

Aynı sütunla başlayan satırları birleştirmek istiyorum. Katıldıktan sonra yalnızca ilk sütun tutulur (bu durumda aaa, www, hhh).

Dosya boşluk veya sekmeyle ayrılmış olabilir.

Örnek girdi:

aaa bbb ccc ddd NULL NULL NULL
aaa NULL NULL NULL NULL NULL NULL
aaa bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy
hhh 111 333 yyy ooo hyy NULL

Istenilen çıktı:

aaa bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL

Bunun arkaplanı, ilk sütunun her zaman varlık için tanımlayıcı olduğu çok basit bir dosya tabanlı veritabanı kurmak istememdir. Aynı tanımlayıcı sütununa dayanan tüm satırlar birleştirilir.


1
nerede vermedi uuuhattı (çıktıda) geliyor?
saeedn

Üzgünüm benim hatam. Ben düzenleyeceğim.
minik

Yanıtlar:


8

Her satırdaki ilk sütunları awk kullanarak almak için aşağıdakileri yapabilirsiniz:

< testfile awk '{print $1}'
aaa
aaa
aaa
www
hhh
hhh

Bunlar hatların geri kalanı için anahtarlarınızdır. Böylece, ilk sütunu anahtar olarak ve ikinci sütunu değer olarak kullanarak bir karma tablo oluşturabilirsiniz:

< testfile awk '{table[$1]=table[$1] $2;} END {for (key in table) print key " => " table[key];}'
www => yyy
aaa => bbbNULLbbb
hhh => 111111

Sütun 2'den başlayarak çizginin geri kalanının tamamını elde etmek için tüm sütunları toplamanız gerekir:

< testfile awk '{line="";for (i = 2; i <= NF; i++) line = line $i " "; table[$1]=table[$1] line;} END {for (key in table) print key " => " table[key];}'
www => yyy hhh NULL NULL NULL NULL 
aaa => bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc    NULL NULL NULL NULL 
hhh => 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL 

Merhaba, evet gerçekten karma tablolar için arıza gerekiyordu. Teşekkür ederim!
minik

2
@tiny - Siparişin korunması gerektiğini varsayıyordum. Durum böyle değil mi (bu cevap orijinal siparişinize değil, karma mekanizmasına karşılık gelen sipariş üretiyor)?
ire_and_curses

3

Birisi awk veya sed ile cevap verebilir, ancak bir Python sürümü basittir ve size yardımcı olabilir.

#!/usr/bin/env python

input_file = 'input.dat'
in_fh      = open(input_file, 'r')

input_order = []
seen        = {}
for line in in_fh:    
    # Remove the newline character...
    line = line[:-1]

    # Separate the first column from the rest of the line...
    key_col, sep, rest_of_line = line.partition(" ")
    rest_of_line = sep + rest_of_line  

    # If we've seen this key already, concatenate the line...
    if key_col in seen:
        seen[key_col] += rest_of_line
    # ...otherwise, record the ordering, and store the new info
    else:
        input_order.append(key_col)
        seen[key_col] = rest_of_line

in_fh.close()

# Dump the ordered output to stdout
for unique_col in input_order:
    print unique_col + seen[unique_col]

Çok havalı. Benim sıfır deneyim python ile bile girdi dosya adı olarak ilk argüman alır betiği düzenlemek başardı :)
küçük

2

Bu, coreutils'in daha ilginç bir uygulamasıdır, girişteki her satır için birleştirmeyi çağırdığı için büyük girdi ile çok verimli olmadığından şüpheleniyorum.

touch outfile
while read; do
  join -a1 -a2 outfile <(echo $REPLY) > tmp
  mv tmp outfile
done < infile

Verimliliğini artırmak için tasarruf etmek outfileve tmpbir ramdiske yardımcı olabilir.

Düzenle

Veya geçici dosyalar olmadan:

out=""
while read; do
  out=$(join -a1 -a2 <(echo -n "$out") <(echo -n "$REPLY"))
done < infile

echo "$out"

2

Ve işte bir PERL tek katlı:

$ perl -e 'my %h; while(<>){chomp; @a=split(/\s+/); $k=shift(@a); $h{$k}.=join(" ", @a) . " "; } map{$h{$_}=~s/\s*$//; print "$_ $h{$_}\n}keys(%hash);' infile
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.