2016-04-11 7 views
1

Ich möchte sed als Teil der Pipeline verwenden, um nur 10 erste und 10 letzte Zeilen seiner Eingabe zu erhalten. Es würde nicht an physischen Dateien arbeiten, sondern nur von STDIN lesen und an STDOUT ausgeben. Die Datenmenge im Stream ist größer als der Arbeitsspeicher der Maschine (oder der Speicherplatz auf der Festplatte). Daher muss sie relativ effizient sein. Es muss auch im Stream-Modus arbeiten, ohne temporäre Dateien zu erstellen (keine schreibbaren Dateisysteme).Entfernung nur die Mitte der Datei mit sed

Extra-Bonus, wenn es eine Zeile anstatt alle der Mitte zeigen konnte es gelöscht:

zum Beispiel, wenn ich die Eingangsleitungen hatte Zahlen von 1 bis 100.000 enthält, ich es Ausgang (Linie mit wörtlichen benötigen würde <cut> Text wäre schön, ist aber optional):

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

Das beste, was ich habe kommen mit ist es Ausgangs ersten 10 Zeilen zu haben, und zuletzt eine 1 Zeile mit:

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

die

 1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
100000 

ausgibt, aber ich brauche es mehr Kontext Ausgang (10 Zeilen statt nur 1) am Ende der Daten zu.

Update: Länge des Eingabestroms ist unbekannt und wird variieren, 100000 oben ist nur ein Beispiel.

aktualisieren: wie in der Frage und den Tag erwähnt, ich brauche es in sed, nicht awk, Perl oder andere Programmiersprachen, in denen es leicht zu erreichen (diese Anforderung ist, zusammen ohne tmp-Dateien ist es System mit begrenzten Befehlen und Ressourcen aufgrund Verfügung Tatsache eingebettet ist)

aktualisieren: wenn der Eingang ist weniger dann, dass 10 + 10 Zeilen, sollte es im Idealfall nur den gesamten Eingang

Antwort

3

Sie folgenden Befehl versuchen:

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

zwei Blöcke haben Inhalte zu speichern, Musterraum und Halteraum. Der erste wird verwendet, um die aktuelle Zeile zu analysieren, und der zweite kann als Backup verwendet werden. Der Ansatz besteht darin, in Speicherplatz die letzten zehn verarbeiteten Zeilen zu speichern.

H speichert jede Zeile zu Halteraum, g erholen Halteraum, dann älteste Linie entfernen und wieder zu Halteraum, und in letzter Zeile speichern ($) druckt Zauberwort vor ihm hinzufügen .

Der ganze Befehl:

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

Ausbeuten:

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

und sagte, dass die Beratung von Ed Morton, folgen, weil einfacher und leichter zu debuggen oder einige Wochen später ändern.


UPDATE:

Sie können halten anhängen Raum nach der ersten zehn Zeilen und prüfen, ob es mehr als 10 Zeilenumbrüche in es vor älteste als FIFO-Struktur zu entfernen:

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

Jetzt ist es schwieriger zu wissen, wo die <cut> Zeichenfolge im Randfall von 20 Eingangslinien hinzuzufügen, aber ich werde es als Übung für y verlassen ou.

+0

Danke! Wenn ich eine Wahl gehabt hätte, würde ich es in lesbarem Perl machen (es kann wirklich existieren :), aber ich bleibe bei sed. Das sieht fast perfekt aus, ist aber anomal, wenn die Eingabe beispielsweise nur 15 Zeilen hat. Ich weiß, ich dehne es hier für sed, aber ist es möglich, dass es nur die gesamte Eingabe druckt, anstatt Zeilen zu duplizieren? –

+0

@MatijaNalis: Ich habe meine Antwort aktualisiert. – Birei

3

druckt sed ist für einfache Substitutionen in einer einzigen Zeile, das ist alles. Für alles andere, einschließlich dieser Aufgabe sollten Sie awk werden:

$ 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 

ich sehe, Sie haben hinzugefügt, um eine „es sed hat zu“ Anforderung auf Ihre Frage, aber ich werde diese Antwort hier für zukünftige Leser hinterlassen Suche nach einem vernünftigen Weg, um die Aufgabe zu erfüllen.