Wie kann ich einen vorgegebenen Bereich von Zeilen aus einer Textdatei auf Unix extrahieren?
-
01-07-2019 - |
Frage
Ich habe einen ~ 23000 Linie SQL-Dump mehr Datenbanken im Wert von Daten enthält. Ich brauche einen bestimmten Abschnitt dieser Datei zu extrahieren (das heißt, die Daten für eine einzelne Datenbank) und es in einer neuen Datei zu platzieren. Ich weiß, dass sowohl die Start- und End-Zeilennummern der Daten, die ich will.
Kennt jemand einen Unix-Befehl (oder eine Reihe von Befehlen), um alle Zeilen aus einer Datei zwischen etwa Zeile zu extrahieren 16224 und 16482 und dann leiten Sie sie in eine neue Datei?
Lösung
sed -n '16224,16482p;16483q' filename > newfile
Von den sed Handbuch :
p - Drucken Sie den Musterraum (auf die Standardausgabe). Dieser Befehl wird in der Regel nur in Verbindung mit der -n-Befehlszeilenoption verwendet wird.
n - Wenn die automatische Druck nicht deaktiviert ist, drucken Sie das Musterraum, dann, unabhängig, ersetzen Sie den Musterraum mit der nächsten Eingabezeile. Wenn gibt es nicht mehr Eingabe dann sed beendet, ohne jede weitere Verarbeitung Befehle.
q - Verlassen
sed
ohne Verarbeitung keine weiteren Befehle oder Eingabe. Beachten Sie, dass der aktuelle Musterraum gedruckt wird, wenn Auto-Druck wird nicht mit der Option -n deaktiviert.
Adressen in einem sed-Skript in einer der folgenden Formen annehmen kann:
Nummer eine Zeilennummer Angeben wird in der Eingabe nur diese Zeile entspricht.
Ein Adressbereich kann durch Angabe zwei Adressen angegeben werden durch ein Komma (,) getrennt. Ein Adressbereich entspricht Linien ausgehend von wo die erste Adresse übereinstimmt, und wird fortgesetzt, bis die zweite Adresse übereinstimmt (einschließlich).
Andere Tipps
sed -n '16224,16482 p' orig-data-file > new-file
Wo 16224,16482 die Startzeilennummer und End-Zeilennummer sind inklusive. Dies ist ein indiziertes. -n
unterdrückt die Eingabe als Ausgabe Echo, die Sie eindeutig nicht wollen; Die Zahlen geben den Zeilenbereich den folgenden Befehl operieren zu machen; der Befehl p
die entsprechenden Zeilen druckt.
Ganz einfach mit Kopf / Schwanz:
head -16482 in.sql | tail -258 > out.sql
mit sed:
sed -n '16482,16482p' in.sql > out.sql
mit awk:
awk 'NR>=10&&NR<=20' in.sql > out.sql
könnten Sie verwenden 'vi' und dann den folgenden Befehl ein:
:16224,16482w!/tmp/some-file
Alternativ:
cat file | head -n 16482 | tail -n 258
EDIT: - Just Erklärung hinzuzufügen, verwenden Sie head -n 16482 angezeigt werden zunächst 16.482 Zeilen dann tail -n verwenden 258 bekommen letzten 258 Zeilen aus der erster Ausgang.
Es gibt einen anderen Ansatz mit awk
:
awk 'NR==16224, NR==16482' file
Wenn die Datei sehr groß ist, kann es gut sein, nach dem exit
die letzte gewünschte Zeile zu lesen. Auf diese Weise wird es die folgenden Zeilen nicht unnötig lesen:
awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
perl -ne 'print if 16224..16482' file.txt > new_file.txt
# print section of file based on line numbers
sed -n '16224 ,16482p' # method 1
sed '16224,16482!d' # method 2
sed -n '16224,16482p' < dump.sql
cat dump.txt | head -16224 | tail -258
sollte es tun. Der Nachteil dieses Ansatzes ist, dass Sie die Arithmetik tun müssen, das Argument für Schwanz zu bestimmen und zu berücksichtigen, ob Sie die ‚zwischen‘ gehört die Endlinie wollen oder nicht.
Schnell und schmutzig:
head -16428 < file.in | tail -259 > file.out
Wahrscheinlich nicht der beste Weg, es zu tun, aber es sollte funktionieren.
BTW:. 259 = 16.482 bis 16.224 + 1
Ich schrieb ein Programm Haskell genannt Splitter , das genau dies: eine lesen Sie durch meine Freilassung Blog-Post .
Sie können das Programm wie folgt verwenden:
$ cat somefile | splitter 16224-16482
Und das ist alles, was es dazu gibt. Sie Haskell brauchen, es zu installieren. Nur:
$ cabal install splitter
Und du bist fertig. Ich hoffe, dass Sie dieses Programm nützlich finden.
Auch können wir dies tun auf der Kommandozeile zu überprüfen:
cat filename|sed 'n1,n2!d' > abc.txt
Beispiel:
cat foo.pl|sed '100,200!d' > abc.txt
Mit Rubin:
ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
auf den Schultern von boxxar Stehend, Ich mag diese:
sed -n '<first line>,$p;<last line>q' input
z.
sed -n '16224,$p;16482q' input
Die $
bedeutet „letzte Zeile“, so der erste Befehl macht sed
Druck alle Linien mit Linien 16224
beginnen und der zweite Befehl machen sed
beenden nach Druckzeile 16428
. (Das Hinzufügen 1
für den q
-Bereich in boxxar Lösung scheint nicht notwendig zu sein.)
Ich mag diese Variante, weil ich nicht zweimal das Ende Zeilennummer angeben. Und ich gemessen, dass $
verwenden, haben keine schädlichen Auswirkungen auf die Leistung.
Ich war über den Kopf / Schwanz Trick zu schreiben, aber eigentlich würde ich wahrscheinlich nur Emacs anwerfen. ; -)
- esc - x goto-line ret 16224
- kennzeichnen ( ctrl - Raum )
- esc - x goto-line ret 16482
- esc - w
Um die neue Ausgabedatei öffnen, ctl-y speichern
Lassen Sie uns mich sehen, was passiert.
Ich würde verwenden:
awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt
FNR enthält der Datensatz (Zeile) Nummer der Zeile aus der Datei gelesen werden.
Ich schrieb einen kleinen Bash-Skript, die Sie von der Kommandozeile ausgeführt werden können, so lange, wie Sie Ihre PATH aktualisieren sein Verzeichnis aufzunehmen (oder Sie können es in einem Verzeichnis abgelegt werden, die bereits im PATH enthalten ist).
Verbrauch: $ Pinch Dateiname Start-Zeilenende-line
#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon
FILENAME=$1
START=$2
END=$3
ERROR="[PINCH ERROR]"
# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
echo "$ERROR Need three arguments: Filename Start-line End-line"
exit 1
fi
# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
echo -e "$ERROR File does not exist. \n\t$FILENAME"
exit 1
fi
# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
echo -e "$ERROR Start line is greater than End line."
exit 1
fi
# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
echo -e "$ERROR Start line is less than 0."
exit 1
fi
# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
echo -e "$ERROR End line is less than 0."
exit 1
fi
NUMOFLINES=$(wc -l < "$FILENAME")
# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
echo -e "$ERROR End line is greater than number of lines in file."
exit 1
fi
# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))
# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
< "$FILENAME" head -n $END | tail -n +$START
else
< "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi
# Success
exit 0
Dies könnte für Sie arbeiten (GNU sed):
sed -ne '16224,16482w newfile' -e '16482q' file
oder nutzen bash unter:
sed -n $'16224,16482w newfile\n16482q' file
Ich wollte das Gleiche von einem Skript tun, um eine Variable und erreichte es durch Anführungszeichen um die Variable $ setzen Sie die Variablennamen aus dem p zu trennen:
sed -n "$first","$count"p imagelist.txt >"$imageblock"
Ich wollte eine Liste in separate Ordner teilen und fand die erste Frage und einen nützlichen Schritt beantworten. (Split-Befehl keine Option auf dem alte o ich Port-Code muß).
Die -n in den akzeptieren Antworten arbeiten. Hier ist eine andere Art und Weise, wenn Sie geneigt sind.
cat $filename | sed "${linenum}p;d";
Dies geschieht Folgendes:
- Rohr in dem Inhalt einer Datei (oder im Text füttern, wie Sie wollen).
- sed wählt die gegebene Linie, druckt er
- d ist erforderlich, Zeilen zu löschen, andernfalls übernehmen sed alle Zeilen schließlich gedruckt werden. das heißt, ohne d, finden Sie alle Linien durch die gewählte Linie zweimal gedruckt gedruckt bekommen, weil Sie die $ {linenum} p Teil haben zu fragen für sie gedruckt werden. Ich bin mir ziemlich sicher, dass die -n ist im Grunde das gleiche wie das d hier tun.
Da sprechen wir über Textzeilen aus einer Textdatei zu extrahieren, werde ich einen Sonderfall geben, wo Sie alle Linien extrahieren mögen, die ein bestimmtes Muster entsprechen.
myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile
Wird die [Daten] Leitung und die restlichen drucken. Wenn Sie den Text von line1 das Muster mögen, geben Sie ein: sed -n '1 / Daten / p' myfile. Außerdem, wenn Sie zwei Muster wissen (besser in Ihrem Text eindeutig sein), die beide Anfang und Ende Zeile des Bereichs kann mit Streichhölzern angegeben werden.
sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
Ich denke, diese nützliche Lösung sein könnte. Wenn der Tabellenname „Person“ ist, können Sie sed verwenden, um alle Zeilen, die Sie benötigen, um Ihre Tabelle wieder her.
sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql > new_data.sql
Basierend auf diese Antwort , wo es die „DROP TABLE IF EXIST“ für die Tabelle fehlt die Sie wiederherstellen und müssen Sie einige Zeilen aus dem Boden der neuen Datei löschen, bevor es zu verhindern, dass mit Hilfe der folgenden Tabelle zu löschen.
Detaillierte Informationen finden Sie auch hier