2016-04-11 25 views
1

Sadece 10 ilk ve 10 son girişini korumak için boru hattının bir parçası olarak sed kullanmak istiyorum. Fiziksel dosyalar üzerinde çalışmıyor, sadece STDIN'den okuyor ve STDOUT'a çıktı. Akıştaki veri miktarı makine RAM'inden (veya disk alanından) daha büyüktür, bu nedenle nispeten verimli olması gerekir. Ayrıca geçici dosyalar (yazılabilir dosya sistemleri yok) oluşturmadan akış modunda çalışmalıdır.Dosyanın sadece ortasından kaldırılıyor

Ekstra Bonus yerine silinmiş ortasında tüm bir satır görüntüler eğer: Ben 100000 1'den numaralarını içeren giriş hatlarını olsaydı

örneğin, ben edebi ile çıkışa (hat için gerekir <cut> metin) olmak güzel, ama isteğe bağlıdır olacaktır:

yes ' ' | head -n 100000 |nl | \ 
    sed -e '$q;11,$d'` 
:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
<cut> 
99991 
99992 
99993 
99994 
99995 
99996 
99997 
99998 
99999 
100000 

I ile geldim iyi ile o çıktı ilk 10 çizgiler ve sonuncusu 1 hattı olması

 1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
100000 

verir

ama çıktı daha bağlamda çok veri sonunda (yerine 1 10 hatları) gerek.

Güncelleştirme: Giriş akışının uzunluğu bilinmiyor ve değişecektir, yukarıdaki 100000 sadece bir örnektir.

Güncelleme: Söz ve etiketinde belirtildiği gibi, ben içinde lüzum yok tmp dosyaları ile birlikte awk, daha kolay olduğu perl veya diğer programlama dilleri (bu şartı yerine getirmek için değil, sed Aslında mevcut kısıtlı komutları ve kaynakları)

Güncelleme ile sisteme gömülü olduğu nedeniyle şöyledir: girdi o 10 + 10 satır altında olması durumunda, bu ideal sadece sed bütün giriş

cevap

3

Sen komutunun ardından deneyebilirsiniz:

sed -n 'H; 1,10 { p; b }; g; s/\n[^\n]*//; h; $ { s/\n/<cut>\n/; p }' 

içeriği kaydetmeyi iki blok, desen uzay ve tutun uzay sahiptir. Birincisi akım hattını ayrıştırmak için kullanılır, ikincisi ise yedek olarak kullanılabilir. Yaklaşım, tutma alanında tutma alanında işlenen son on satırı kaydetmektir.

H

tutun alanı, g kurtarmak tutun uzay için her satırını kaydeder, daha sonra eski çizgiyi kaldırıp tutun alanı tekrar kaydedin ve son satırında ( $) baskı önündeki sihirli kelime ekleyerek .

bütün komut:

yes ' ' | head -n 100000 |nl|\ 
    sed -n 'H; 1,10 { p; b }; g; s/\n[^\n]*//; h; $ { s/\n/<cut>\n/; p }' 

Verim:

 1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
<cut> 
99991 
99992 
99993 
99994 
99995 
99996 
99997 
99998 
99999 
100000 

Ve debug daha basit ve daha kolay olduğu için, Ed Morton tavsiyelerini uygulamak ya da bazı hafta sonra değiştirmek söyledi.


GÜNCELLEME:

İlk on satırdan sonra beklemeye uzay eklenecek ve FIFO yapı olarak eski çıkarmadan önce onun içinde 10'dan fazla satır karakterlerinin olup olmadığını kontrol edebilirsiniz:

sed -n '1,10 { p; b }; H; g; /\(\n[^\n]\+\)\{11\}/ s/\n[^\n]*//; h; $ { s/^\n//; p }' 

Şimdi 20 giriş satırının kenarına <cut> dizesini eklemeyi bilmek daha zor, ancak ben y için bir egzersiz olarak bırakacağım ou.

+0

Teşekkürler! Eğer bir seçim yapsaydım eğer okunabilir perlde yapardım (gerçekten var olabilir), ama ben sed ile sıkışıp kaldım. Bu neredeyse mükemmel görünüyor, ancak giriş sadece 15 satır olduğunda anormal. Burada sed için uzandığımı biliyorum, ancak kopyaları çoğaltmak yerine tüm girdiyi yazdırmak mümkün mü? –

+0

@MatijaNalis: Cevabımı güncelledim. – Birei

3

olduğunu yazdırmalısınız Tek bir satırdaki basit ikameler için, hepsi bu. Ben Sorunuza "sed olmak o gelmiştir" şartını ekledik ama gelecek okuyucular için buraya bu cevabı bırakacağım bkz

$ cat tst.awk 
BEGIN { beg=(beg?beg:3); end=(end?end:3) } 
NR<=beg 
{ rec[(NR-1)%end+1] = $0 } 
END { 
    print "<cut>" 
    for (i=1;i<=end;i++) { 
     print rec[(NR+i-1)%end+1] 
    } 
} 

$ seq 10 | awk -f tst.awk 
1 
2 
3 
<cut> 
8 
9 
10 

$ seq 10 | awk -v beg=2 -v end=4 -f tst.awk 
1 
2 
<cut> 
7 
8 
9 
10 

: Bu görev de dahil olmak üzere başka bir şey, için, awk kullanıyor olmalıdır görevi yerine getirmek için mantıklı bir yol arıyorum.

İlgili konular