Drucken Sie ungerade Zeilen und gerade Zeilen


18

Ich möchte die ungeraden und geraden Zeilen aus Dateien drucken.

Ich habe dieses Shell-Skript gefunden, das Echo verwendet.

#!/bin/bash
# Write a shell script that, given a file name as the argument will write
# the even numbered line to a file with name evenfile and odd numbered lines
# in a text file called oddfile.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------

file=$1
counter=0

eout="evenfile.$$" # even file name
oout="oddfile.$$" # odd file name

if [ $# -eq 0 ]
then
    echo "$(basename $0) file"
    exit 1
fi

if [ ! -f $file ]
then
    echo "$file not a file"
    exit 2
fi

while read line
do
    # find out odd or even line number
    isEvenNo=$( expr $counter % 2 )

    if [ $isEvenNo -ne 0 ]
    then
        # even match
        echo $line >> $eout
    else
        # odd match
        echo $line >> $oout
    fi
    # increase counter by 1
    (( counter ++ ))
done < $file
echo "Even file - $eout"
echo "Odd file - $oout"

Aber gibt es keine Möglichkeit, dies in einer Zeile zu tun?

Ja, benutze awk, ich lese.

Gerade Zeilen:

awk 'NR % 2' filename

ungeradzahlige Zeilen:

awk 'NR % 2 == 1' filename

Aber bei mir funktioniert es nicht. Beide erzeugen die gleiche Ausgabe, laut Diff. Im Vergleich zur Originaldatei sind beide tatsächlich halb so lang und enthalten die ungeradzahligen Zeilen. Mache ich etwas falsch?


6
Das erste sollte sein NR % 2 == 0, sonst ist es gleichbedeutend mit dem zweiten.
Enzotib

Anscheinend sind mehrere Dokumente online (einschließlich dieses), die oben in einer Suche angezeigt werden und besagen, dass NR% 2 die geraden Zeilen enthält, was nicht korrekt ist. Dies ist ungerade, da 1% 2 = 1 = wahr, 2% 2 = 0 = falsch.
Delta

Antworten:


12

Wie Sie "in einer Zeile" gefragt haben:

awk '{print>sprintf("%sfile.%d",NR%2?"odd":"even",PROCINFO["pid"])}' filename

Beachten Sie, dass der größte Teil des Codes auf Ihre ausgefallene Wahl des Ausgabedateinamens zurückzuführen ist. Andernfalls würde der folgende Code ausreichen, um ungerade Zeilen in "Zeile-1" und gerade Zeilen in "Zeile-0" einzufügen:

awk '{print>"line-"NR%2}' filename

26

Ich bevorzuge es, wenn immer möglich, POSIX-kompatibel zu sein, daher dachte ich, ich würde diese alternative Methode veröffentlichen. Ich verwende diese oft, um Text vor xargsPipelines zu entstellen .

Geradzahlige Zeilen drucken,

sed -n 'n;p'

Drucken von ungeraden Zeilen,

sed -n 'p;n'

Obwohl ich es oft benutze awk, ist es für diese Art von Aufgabe übertrieben.


14

Das ist einfach:

 sed -n 2~2p filename

druckt geradzahlige Zeilen aus dem Dateinamen

sed -n 1~2p filename

druckt ungerade Zeilen.


1
+1, wenn AWK nicht übermäßig verwendet wird. Nicht POSIX sed, aber es ist immer noch eine solide Methode.
JM Becker

@ TechZilla Ich verstehe nicht, "AWK überflüssig zu benutzen" - awk ist auch POSIX.
JW013,

3
@ jw013: Nichts ist falsch daran awk, ich persönlich benutze es sehr oft. Ich habe nie gesagt, dass irgendetwas mit "Nicht POSIX" zu tun awkhat. Ich bezog mich auf die sedOptionen der Antwort . Speziell für den ~Betreiber ist es eine GNU-Erweiterung, die für viele Menschen noch akzeptabel ist. Das "Verwenden von AWK , I personally believe using außerhalb von awk" für diese einfache Aufgabe ist übertrieben. Die +1 war also für die Erfüllung der Aufgabe mit sedeinem leichteren Dienstprogramm als awk.
JM Becker

1
Kann mir bitte jemand erklären, wie ~ operator hier funktioniert?
Für immer Anfänger

9

Für gerade Zahlen sollte der Code sein

awk 'NR%2==0' filename

& für ungerade Zahlen

awk 'NR%2==1' filename

1
Dieser ist perfekt. Selbst wenn Sie Zeilen in Schritten von 10 erhalten müssen, müssen Sie beispielsweise eine bestellte Datei mit einer Größe von 1 Million auf 100.000 reduzieren. Genau das wollte ich.
Dexter

Wie können Sie die geradzahligen Spalten in AWK drucken? Ich kann das nicht zum Laufen bringen gawk 'FS=",";NF%2==0' file.csv.
hhh

2

Sie können dies mit einem einzigen sedAufruf tun , ohne die Datei zweimal lesen zu müssen:

sed '$!n
w even
d' infile > odd

oder, wenn Sie es vorziehen, in einer Zeile:

sed -e '$!n' -e 'w even' -e d infile > odd

Beachten Sie, dass diese nicht das erwartete Ergebnis geben , wenn eine Datei nur eine Zeile enthält (die Linie wird wzu Ritte evenstatt oddals ersten nnicht ausgeführt wird ). Um dies zu vermeiden, fügen Sie eine Bedingung hinzu:

sed -e '$!n' -e '1!{w even' -e 'd}' infile > odd

Wie es funktioniert ? Nun, es werden drei sedBefehle verwendet:
n- Wenn nicht in der letzten Zeile der Musterbereich gedruckt wirdstdout (der in die Datei umgeleitet wird odd), ersetzen Sie ihn durch die nächste Zeile (so dass jetzt eine gerade Zeile verarbeitet wird) und fahren Sie mit der Ausführung der verbleibenden Befehle fort
w- fügen Sie hinzu Zu speichernder Musterbereich even
d- Löschen Sie den aktuellen Musterbereich und starten Sie den Zyklus neu. Der Nebeneffekt ist, dass sedder Musterbereich niemals automatisch gedruckt wird, da er niemals das Ende des Skripts erreicht

Mit anderen Worten nwird nur auf ungeraden Zeilen ausgeführt und wund dwerden nur auf geraden Zeilen ausgeführt. sedEs wird nie automatisch gedruckt, es sei denn, wie gesagt, die Eingabe besteht aus einer einzelnen Zeile.


Könnten Sie bitte erläutern, wie es funktioniert?
Forever Learner

Vielen Dank don_crissti für Ihre Hilfe. Mit freundlichen Grüßen schätzen es, als auch positiv bewertet.
Für immer Anfänger

0

Versuche dies:

awk '{if(NR%2){print $0 > "odd.file"}else{print $0 > "even.file"}}' filename

Sind Sie sicher, dass Sie die Datensatznummern ausgeben möchten?
manatwork

Tut mir leid, ich habe es so geändert, dass es die ganzen Zeilen ausgibt.
Renma

0

Ich würde mitgehen, perlweil ich mag perl:

perl -pe 'BEGIN{open($e,">even_lines");open($o,">odd_lines")} $. % 2 ?select $o:select $e;'

Verwendet die Tatsache, dass -pimplizit gedruckt wird, um zu replizieren, wie es sedfunktioniert - und wir verwenden selectsie, um zu wählen, in welches Dateihandle geschrieben wird.

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.