Awk - gibt die zweite Zeile einer Reihe von .dat-Dateien in eine Datei aus


9

Ich habe mehrere Dateien wie: (in Wirklichkeit habe ich 80)

file1.dat

2 5

6 9

7 1

file2.dat

3 7

8 4

1 3

Ich möchte mit einer Datei enden, die alle zweiten Zeilen enthält. dh

output.dat

6 9

8 4

Was ich bisher habe, schleift zwar die Dateinamen, überschreibt dann aber die Datei davor. zB wäre die Ausgabe der oben genannten Dateien nur

8 4

Mein Shell-Skript sieht folgendermaßen aus:

post.sh

TEND = 80

TINDX = 0

while [ $TINDX - lt $TEND]; do

awk '{ print NR==2 "input-$TINDX.dat > output.dat

TINDX = $((TINDX+1))

done

Antworten:


17

Entfernen Sie die whileSchleife und verwenden Sie die Erweiterung der Schalenstrebe sowie FNReine integrierte awkVariable:

awk 'FNR==2{print $0 > "output.dat"}' file{1..80}.dat

9
noch kürzerawk 'FNR==2' file{1..80}.dat > output.dat
Archemar

7

sed wäre genug:

sed -sn 2p file{1..80}.dat > output.dat

-s Die Option wird benötigt, um die zweite Zeile aus jeder Datei zu drucken. Andernfalls wird nur die zweite Zeile der ersten Datei gedruckt.


6

Was ist mit ... head -n 2 input.dat | tail -n 1 | awk...


Ja, head/ tailist definitiv eine Option, die Sie dann nicht brauchen awk.
Jimmyij

2

Die sedLösung von Aragaer ist am schönsten, ja. Aber da ich gerne head|tailschneide, habe ich eine head|tailLösung, die mehrere Dateien unterstützt, nicht nur eine input.dat. Die Verwendung einer for-Schleife, anstatt eine Liste von Dateien an sed zu übergeben, erleichtert es auch, andere Dinge mit der Datei vor / nach dem Extrahieren der zweiten Zeile mit sed zu tun.

# empty output.dat first
rm output.dat

# have a one-liner
for file in *.dat; do head -2 $file | tail -1 >> output.dat; done 

Reichlich kommentierte mehrzeilige Version:

NB: Der folgende Code wird ausgeführt. Es steht uns frei, nach a |, &&oder einen Zeilenumbruch zu setzen ||und unseren Befehl in der nächsten Zeile fortzusetzen. wir können sogar Kommentare dazwischen setzen. Ich habe Jahre damit verbracht, das nicht zu wissen (und es nirgendwo wirklich zu sehen). Dieser Stil ist an der interaktiven Eingabeaufforderung weniger nützlich, bereinigt jedoch Skriptdateien ohne Ende.

# empty output.dat first
rm output.dat

for file in *.dat; do
    # file -> lines 1 and 2 of file
    head -2 $file |
    # lines 1 and 2 of file -> line 2 of file >> appended to output.dat
    tail -1 >> output.dat
done

0

Es gibt offensichtlich viele Möglichkeiten, dies zu tun - ich denke, ich mag @ aragaers sed Antwort am besten .

Hier ist eine, die rein bash-integrierte Funktionen verwendet und keine externen Dienstprogramme benötigt:

for f in file{1..80}.dat; do
    { read && read && printf "%s\n" "$REPLY"; } < "$f"
done > output.dat

0

Um die Verwendung von awkund sedin Antworten hier für mehrere Dateien effizienter zu gestalten, sollten Sie die nextfileAnweisung verwenden, um die Verarbeitung unerwünschter Zeilen zu überspringen awk.

awk 'FNR==2{ print >"output.dat"; nextfile}' infile{1..80}.dat

und mit sedkönnen wir bei der Verarbeitung in der 3. Zeile beenden und seddie nächste Datei verarbeiten.

sed -sn '2p;3q' infile{1..80}.dat > output.dat
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.