Awk: genera la seconda riga di un numero di file .dat su un file


9

Ho più file qualcosa del tipo: (in realtà ne ho 80)

file1.dat

2 5

6 9

7 1

file2.dat

3 7

8 4

1 3

Voglio finire con un file contenente tutte le seconde righe. vale a dire

output.dat

6 9

8 4

Quello che ho finora scorre attraverso i nomi dei file ma poi sovrascrive il file prima di esso. ad esempio, l'output dei file sopra sarebbe solo

8 4

il mio script shell è simile al seguente:

post.sh

TEND = 80

TINDX = 0

while [ $TINDX - lt $TEND]; do

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

TINDX = $((TINDX+1))

done

Risposte:


17

Rimuovere il whileloop e utilizzare l'espansione del controvento della shell e anche FNRuna awkvariabile integrata :

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

9
ancora più breveawk 'FNR==2' file{1..80}.dat > output.dat
Archemar,

7

Che dire di ... head -n 2 input.dat | tail -n 1 | awk...


Sì, head/ tailè sicuramente un'opzione, non è necessario awkquindi.
Jimmij,

7

sed sarebbe abbastanza:

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

-s è necessaria l'opzione per stampare la seconda riga da ciascun file, altrimenti verrà stampata solo la seconda riga del primo file.


2

la sedsoluzione di Aragaer è la migliore, sì. Ma da quando mi piace un po 'di head|tailtaglio, ho una head|tailsoluzione che supporta più file, non solo uno input.dat. L'uso di un ciclo continuo, invece di passare un elenco di file a sed, rende anche più semplice fare altre cose con il file prima / dopo l'estrazione della seconda riga con sed.

# empty output.dat first
rm output.dat

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

Versione multilinea ampiamente commentata:

NB: verrà eseguito il codice seguente. Siamo liberi di mettere un'interruzione di linea, dopo una |, &&o ||, e continuare il nostro comando sulla riga successiva; possiamo anche inserire commenti tra. Ho passato anni a non saperlo (e non vederlo da nessuna parte). Questo stile è meno utile al prompt interattivo, ma pulisce i file di script senza fine.

# 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

Ci sono ovviamente molti modi per farlo - penso che mi piaccia la risposta sed @ aragaer al meglio .

Eccone uno che utilizza builtin puramente bash e non ha bisogno di fork di utilità esterne:

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

0

Per l'uso di efficienza awke seddi risposte qui su più file, meglio usare nextfiledichiarazione per saltare l'elaborazione di linee indesiderate in awk.

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

e con sed, possiamo uscire durante l'elaborazione su 3 ° riga ed sedelaborare il file successivo.

sed -sn '2p;3q' infile{1..80}.dat > output.dat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.