it-swarm.com.de

So behalten Sie nur jede n-te Zeile einer Datei

Ich habe eine ziemlich große CSV-Datei (75 MB). Ich versuche nur, ein Diagramm davon zu erstellen, daher brauche ich wirklich nicht alle Daten.

Neuformulierung: Ich möchte n Zeilen löschen, dann eine Zeile behalten, dann n Zeilen löschen und so weiter.

Also, wenn die Datei so aussah:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6

und n = 2, dann wäre die Ausgabe:

Line 3
Line 6

Anscheinend kann sed das, aber ich habe nicht herausgefunden, wie. Ein Bash-Befehl wäre ideal, aber ich bin offen für jede Lösung.

67
Computerish
~ $ awk 'NR == 1 || NR % 3 == 0' yourfile
Line 1
Line 3
Line 6

NR (Anzahl der Datensätze) Variable ist die Anzahl der Datensätze, da das Standardverhalten eine neue Zeile für RS (Datensatztrenner) ist. Muster und Aktion sind in awks Standardformat 'pattern {actions}' optional. Wenn wir nur einen Musterteil angeben, schreibt awk alle Felder $0 für die true-Bedingungen unseres Musters.

115
Selman Ulug

sed kann dies auch:

$ sed -n '1p;0~3p' input.txt
Line 1
Line 3
Line 6

man sed erklärt ~ als:

first ~ step Stimmt mit jeder Zeile überein, die mit der ersten Zeile beginnt. Beispiel: "sed -n 1 ~ 2p" gibt alle ungeraden Zeilen im Eingabestream aus, und die Adresse 2 ~ 5 stimmt mit jeder fünften Zeile überein, beginnend mit der zweiten. Erstens kann Null sein. sed verhält sich in diesem Fall so, als wäre es gleich step. (Dies ist eine Erweiterung.)

55
kev

Perl kann dies auch:

while (<>) {
    print  if $. % 3 == 1;
}

Dieses Programm gibt die erste Zeile seiner Eingabe und danach jede dritte Zeile aus.

Um es ein bisschen zu erklären, <> ist der Zeileneingabeoperator, der über die Eingabezeilen iteriert, wenn er in einer whilename__-Schleife wie dieser verwendet wird. Die Sondervariable $. enthält die Anzahl der bisher gelesenen Zeilen, und % ist der Moduloperator.

Mit den Schaltern -n und -e kann dieser Code als Einzeiler noch kompakter geschrieben werden:

Perl -ne 'print if $. % 3 == 1'  < input.txt  > output.txt

Der Schalter -e benötigt einen Teil des Perl-Codes, um als Befehlszeilenparameter ausgeführt zu werden, während der Schalter -n den Code implizit in eine whilename__-Schleife einschließt, wie oben gezeigt.


Bearbeiten: Um tatsächlich die Zeilen 1, 3, 6, 9, ... wie im Beispiel zu erhalten, anstatt die Zeilen 1, 4, 7, 10, ..., wie ich zuerst angenommen habe, ersetzen Sie $. % 3 == 1 durch $. == 1 or $. % 3 == 0.

21
Ilmari Karonen

Wenn Sie es mit einem Bash Skript machen möchten, können Sie versuchen:

#!/bin/sh

echo Please enter the file name
read fname
echo Please enter the Nth lines that you want to keep
read n

exec<$fname
value=0
while read line
do
    if [ $(( $value % $n )) -eq 0 ] ; then
        echo -e "$line" >> new_file.txt
    fi
        let value=value+1 
done
echo "Check the 'new_file.txt' that has been created in this directory";

Speichern Sie es als "read_lines.sh" und denken Sie daran, der Bash-Datei + x-Berechtigungen zu erteilen.

chmod +x ./read_lines.sh
7
akarpovsky

Eine Lösung in Pure Bash, die keinen Prozess hervorbringt, ist:

{ for f in {1..2}; do read line; done;
  while read line; do
    echo $line;
    for f in {1..2}; do read line; done;
  done; } < file

In der ersten Zeile werden 2 Zeilen am Anfang der Datei übersprungen, und die Variable while gibt die nächste Zeile aus und überspringt erneut 2 Zeilen.

Wenn Ihre Datei klein ist, ist dies eine sehr effiziente Methode, um den Job auszuführen, da kein Prozess gestartet wird. Wenn Ihre Datei groß ist, sollte sed verwendet werden, da es effizienter ist, mit io umzugehen als bash.

4
jfg956