Wie wähle ich bestimmte Zeilen (n, n + 4, n + 8, n + 12…) aus der Datei aus?


Antworten:


28

Verwenden von AWK:

awk '!((NR - 1) % 4)' input > output

Herauszufinden, wie dies funktioniert, bleibt dem Leser als Übung überlassen.


danke für diesen kurzen awk kurs!
Darxmurf

20
NR % 4 == 1wäre besser lesbar IMO.
Stéphane Chazelas

12
Einverstanden @ Stéphane; Dies ist wahrscheinlich meinerseits fraglich, aber für möglicherweise Hausaufgabenfragen versuche ich, meine Antworten ein wenig zu verschleiern ...
Stephen Kitt

@StephenKitt Ihre Antworten verschleiern? "Ja wirklich?" Dies ist nicht der richtige Ort dafür.
Daten

22

Verwendung von split (GNU Coreutils):

split -nr/1/4 input > output
  • -nCHUNKSAusgabedateien generieren

und CHUNKSals

  • r/K/N Verwenden Sie die Round-Robin-Verteilung und geben Sie nur Kth von N an stdout aus, ohne Zeilen / Datensätze zu teilen

1
Verblüfft. Antworten wie diese sind, warum ich diese SE liebe. Vielen Dank!
user1717828

21

Mit GNU sed:

sed '1~4!d' < input > output

Mit Standard sed:

sed -n 'p;n;n;n' < input > output

Mit 1und 4in $nund $iVariablen:

sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'

7

Hinzufügen der obligatorischen Perl-Lösung:

perl -ne 'print if $. % 4 == 1' input > output

4

Python-Version, nur zum Spaß:

with open('input.txt') as f:
    for i, line in enumerate(f.readlines()):
        if i%4 == 0:
            print(line.strip())

enumerate(f)sollte in der Lage sein, die Arbeit zu erledigen, während weniger Speicher verbraucht wird
iruvar

@iruvar Das ist so ordentlich! Das habe ich noch nie bemerkt. wird in Zukunft verwendet. Fühlen Sie sich frei, es in diese Antwort zu bearbeiten; Ich werde es nicht wirklich mit Optimierungen aufrechterhalten, da die anderen Bash-Antworten (insbesondere diese ) definitiv der richtige Weg sind.
user1717828

Wenn Sie verwenden readlinesmöchten (wodurch die gesamte Datei in den Speicher geschlürft wird), können f.readlines()[::4]Sie jede vierte Zeile abrufen. So können Sie verwenden print(''.join(f.readlines()[::4])).
Nick Matteo

3

POSIX sed: Diese Methode verwendet das posixly sed und kann daher überall ausgeführt werden, oder zumindest die Samen, die posix respektieren.

 $ sed -ne '
   /\n/!{
    H;s/.*//;x
   }

   :loop
       $bdone
       N;s/\n/&/4
       tdone
   bloop

   :done
   s/.//;P
 ' input.file

Eine andere ist eine programmatische Sed-Code-Generierung für Skalierbarkeitszwecke:

$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file

Perl: Wir füllen Array A auf, bis es 4 groß ist. Dann drucken wir das erste Element und löschen das Array.

$ perl -pe '
   $A[@A] = @A ? <> : $_ while @A < 4;
   $_ = (splice @A)[0];
' input.file

1

Call with scriptname filename skip(4 in Ihrem Fall) Es funktioniert, indem iterZeilen vom Anfang der Datei gezogen und dann nur die letzten ausgegeben werden. Es erhöht dann iterdurch skipsund wiederholt, solange der Wert iternicht überschritten hat das linesin file.

#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
 head "$file" -n $iter | tail -n 1
 iter=$(( $iter + $skips ))
done

1

Pure Bash:

mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done

mapfile ist eine in Bash 4 hinzugefügte integrierte Datei, die Standardeingaben in ein hier genanntes Array linesmit einer Zeile pro Eintrag liest . Die -tOption entfernt die letzten Zeilenumbrüche.

Wenn Sie jede vierte Zeile ab Zeile 4 drucken möchten, können Sie dies in einem Befehl mithilfe mapfileder Rückrufoption tun, bei -Cder der bereitgestellte Code alle paar Zeilen mit dem angegebenen Intervall ausgeführt wird -c. Der aktuelle Array-Index und die nächste zuzuweisende Zeile werden dem Code als Argumente übergeben.

mapfile -t -c4 -C 'printf "%.0s%s\n"' < input

Dies verwendet das printfeingebaute; Der Formatcode %.0sunterdrückt das erste Argument (den Index), sodass nur die Zeile gedruckt wird.

Sie könnten den gleichen Befehl verwenden, um jede vierte Zeile ab Zeile 1, 2 oder 3 zu drucken, aber Sie müssten 3, 2 oder 1 Zeilen voranstellen, inputbevor Sie sie eingeben mapfile, was meiner Meinung nach mehr Probleme als wert ist .

Dies funktioniert auch:

mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"

Hier werden printfvier Einträge des Arrays linesgleichzeitig verbraucht , wobei nur der erste gedruckt und die anderen drei mit übersprungen werden %.0s. Ich mag das nicht, da Sie für verschiedene Intervalle oder Startpunkte manuell mit der Formatzeichenfolge herumspielen müssen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.