Zeile für Zeile extrahieren und dann in einer separaten Datei speichern

Zeile für Zeile extrahieren und dann in einer separaten Datei speichern

Ich habe mein Glück mit grepund versucht, sedaber irgendwie bekomme ich es nicht hin.

Ich habe eine Protokolldatei mit einer Größe von etwa 8 GB. Ich muss einen 15-minütigen Zeitraum verdächtiger Aktivitäten analysieren. Ich habe den Teil der Protokolldatei gefunden, den ich mir ansehen muss, und versuche, diese Zeilen zu extrahieren und in einer separaten Datei zu speichern. Wie würde ich das auf einer normalen CentOS-Maschine machen?

Mein letzter Versuch war dieser, aber er hat nicht funktioniert. Ich bin ratlos, wenn es um seddiese Art von Befehlen geht.

sed -n '2762818,2853648w /var/log/output.txt' /var/log/logfile

Antwort1

sed -n '2762818,2853648p' /var/log/logfile > /var/log/output.txt

pist für den Druck

Antwort2

Der beste Weg hierfür ist wahrscheinlich, wie andere bereits erwähnt haben, die Shell-Umleitung. Dies ist sedzwar mein persönlicher Favorit, wird dies aber vermutlich nicht effizienter erledigen als will head, das darauf ausgelegt ist, nur eine bestimmte Anzahl von Zeilen aus einer Datei zu erfassen.

Auf dieser Site gibt es weitere Antworten, die nachweislich zeigen, dass bei großen Dateien die Leistung immer head -n[num] | tail -n[num]besser ist , aber wahrscheinlich noch schneller ist es, ganz auf die Pipe zu verzichten.sed

Ich habe eine Datei wie diese erstellt:

echo | dd cbs=5000000 conv=block | tr \  \\n >/tmp/5mil_lines

Und ich habe es durchlaufen lassen:

{ head -n "$((ignore=2762817))" >&2
  head -n "$((2853648-ignore))" 
} </tmp/5mil_lines 2>/dev/null  |
sed -n '1p;$p'                

Ich habe seddort nur „überhaupt“ verwendet, um nur die erste und die letzte Zeile zu erfassen und Ihnen zu zeigen …

2762818
2853648

Dies funktioniert, weil Sie Befehle gruppieren { ... ; }und die Eingabe für die Gruppe umleiten, als ... ; } <inputwürden alle dieselbe Eingabe verwenden. Die meisten Befehle verbrauchen beim Lesen die gesamte Eingabedatei, sodass in einem { cmd1 ; cmd2; } <infileFall normalerweise cmd1vom Anfang bis zum Ende der Eingabedatei gelesen wird und cmd2nichts übrig bleibt.

headwird jedoch immer nur so weit in seinem Infile suchen, wie es angewiesen wurde, und so in einem …

{ head -n [num] >/dev/null
  head -n [num]
} <infile 

… Fall sucht der erste bis [num]und gibt seine Ausgabe dorthin aus, /dev/nullund der zweite kann dort mit dem Lesen beginnen, wo der erste aufgehört hat.

Du kannst tun...

{ head -n "$((ignore=2762817))" >/dev/null
  head -n "$((2853648-ignore))" >/path/to/outfile
} <infile

Diese Konstruktion funktioniert auch mit anderen zusammengesetzten Befehlen. Beispiel:

set "$((n=2762817))" "$((2853648-n))"
for n do head "-n$n" >&"$#"; shift
done <5mil_lines 2>/dev/null | 
sed -n '1p;$p'

...der druckt...

2762818
2853648

Es könnte aber auch so funktionieren:

d=$(((  n=$(wc -l </tmp/5mil_lines))/43 ))      &&
until   [ "$(((n-=d)>=(!(s=143-n/d))))" -eq 0 ] &&
        head "-n$d" >>"/tmp/${s#1}.split"
do      head "-n$d" > "/tmp/${s#1}.split"       || ! break
done    </tmp/5mil_lines

Oben setzt die Shell zunächst die $nund $dVariablen auf ...

  • $n
    • wcDie von mir für meine Testdatei gemeldete Zeilenanzahl/tmp/5mil_lines
  • $d
    • Der Quotient von $n/4343 ist lediglich ein beliebig gewählter Teiler.

Anschließend führt es eine Schleife aus, die es um auf einen Wert kleiner untildekrementiert hat . Dabei speichert es seinen Split-Count in und verwendet diesen Wert in der Schleife, um die benannte Ausgabedatei mit dem Namen zu erhöhen . Das Ergebnis ist, dass es für jede Iteration eine gleiche Anzahl von durch Zeilen getrennten Feldern in seiner Eingabedatei in eine neue Ausgabedatei liest – und sie im Verlauf der Schleife 43 Mal gleichmäßig aufteilt. Es schafft dies, ohne seine Eingabedatei mehr als 2 Mal lesen zu müssen – das erste Mal, wenn es seine Zeilen zählt, und für den Rest der Operation liest es nur so viele Zeilen, wie es jedes Mal in die Ausgabedatei schreibt.$n$d$d$s>/tmp/[num].split\nwc

Nachdem ich es ausgeführt hatte, überprüfte ich meine Ergebnisse wie ...

tail -n1 /tmp/*split | grep .

AUSGABE:

==> /tmp/01.split <==
116279  
==> /tmp/02.split <==
232558  
==> /tmp/03.split <==
348837  
==> /tmp/04.split <==
465116  
==> /tmp/05.split <==
581395  
==> /tmp/06.split <==
697674  
==> /tmp/07.split <==
813953  
==> /tmp/08.split <==
930232  
==> /tmp/09.split <==
1046511 
==> /tmp/10.split <==
1162790 
==> /tmp/11.split <==
1279069 
==> /tmp/12.split <==
1395348 
==> /tmp/13.split <==
1511627 
==> /tmp/14.split <==
1627906 
==> /tmp/15.split <==
1744185 
==> /tmp/16.split <==
1860464 
==> /tmp/17.split <==
1976743 
==> /tmp/18.split <==
2093022 
==> /tmp/19.split <==
2209301 
==> /tmp/20.split <==
2325580 
==> /tmp/21.split <==
2441859 
==> /tmp/22.split <==
2558138 
==> /tmp/23.split <==
2674417 
==> /tmp/24.split <==
2790696 
==> /tmp/25.split <==
2906975 
==> /tmp/26.split <==
3023254 
==> /tmp/27.split <==
3139533 
==> /tmp/28.split <==
3255812 
==> /tmp/29.split <==
3372091 
==> /tmp/30.split <==
3488370 
==> /tmp/31.split <==
3604649 
==> /tmp/32.split <==
3720928 
==> /tmp/33.split <==
3837207 
==> /tmp/34.split <==
3953486 
==> /tmp/35.split <==
4069765 
==> /tmp/36.split <==
4186044 
==> /tmp/37.split <==
4302323 
==> /tmp/38.split <==
4418602 
==> /tmp/39.split <==
4534881 
==> /tmp/40.split <==
4651160 
==> /tmp/41.split <==
4767439 
==> /tmp/42.split <==
4883718 
==> /tmp/43.split <==
5000000 

Antwort3

Dies können Sie wahrscheinlich mithilfe der folgenden Befehlskombinationen headerreichen .tail

head -n{to_line_number} logfile | tail -n+{from_line_number} > newfile

Ersetzen Sie das from_line_numberund to_line_numberdurch die gewünschten Zeilennummern.

Testen

cat logfile
This is first line.
second
Third
fourth
fifth
sixth
seventh
eighth
ninth
tenth

##I use the command as below. I extract from 4th line to 10th line. 

head -n10 logfile | tail -n+4 > newfile
fourth
fifth
sixth
seventh
eighth
ninth
tenth

verwandte Informationen