3

I have multiple files with different number or records in each. I want an awk command to print the second last line of them and perform some change. I want something like this:(this one doesn't work of course)

awk '( NR == FNR-1 ), $0","' *.txt

marked as duplicate by αғsнιη, don_crissti, Jeff Schaller, ilkkachu, Kiwy May 23 '18 at 8:50

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    perform some change - what change exactly? – RomanPerekhrest May 22 '18 at 12:54
  • @RomanPerekhrest Append a comma at the end of that line is what I want in this case. Didn't think it would matter though :) – Tejaswi N May 22 '18 at 12:58
  • should each file be modified in-place? – RomanPerekhrest May 22 '18 at 12:59
  • Yes. My main focus is the selection of the second last line.. i.e "( NR == FNR-1 )" this part in my command. What is wrong in that.. But yes I do want to modify them in place. In the description I said I want to print the second last line to just test it on one file and see how it work.. and so that I would later add the part where it adds the comma at the end of that line. – Tejaswi N May 22 '18 at 13:05
  • @αғsнιη Thanks! The awk solution in the mentioned link worked. I missed that page probably because of the different keywords used I suppose. – Tejaswi N May 22 '18 at 13:27
4

awk reads records as they come and has no notion of how far from the end those records are if it has not read them yet (extra records could very well be added after it reads and processes the current record).

Contrary to sed, it cannot even tell which is the last record (sed has the $ address which it actually implements by internally reading one record in advance so it knows which is the last one).

You can however do some processing at the end in the special END statement, or with GNU awk, after having processed each input file (in the ENDFILE statement).

So you can save the last two records while you're processing them, and then in the END/ENDFILE statement, recall the penultimate one from where you've saved it.

For instance:

awk '{prevlast = last; last = $0}
     END {if (NR >= 2) print "penultimate:", prevlast}' < input

Or:

gawk '{prevlast = last; last = $0}
      ENDFILE {
       if (FNR >= 2) print "penultimate for", FILENAME ":", prevlast
      }' file1 file2

Or to generalise it for the nth from the end:

awk -v n=2 '{saved[NR % n] = $0}
     END {if (NR >= n) print saved[(NR + 1) % n]}' < input

gawk -v n=2 '{saved[FNR % n] = $0}
     ENDFILE {if (FNR >= n) print saved[(FNR + 1) % n]}' file1 file2
0

To append comma , at the end of second-to-last line with modifying each file in-place.

sed solution:

Sample file1.txt:

C2-C1 1.5183
C3-C2 1.49
C3-C1 1.4991
O4-C3 1.4104
C1-C2-C3 59.78

Sample file2.txt:

C2-C1 1.5052
C3-C2 1.505
C3-C1 1.5037
S4-C3 1.7976
C1-C2-C3 59.95

sed -i 'x; ${s/.*/&,/;p;x}; 1d' file*.txt

Viewing results:

$ head file[12].txt
==> file1.txt <==
C2-C1 1.5183
C3-C2 1.49
C3-C1 1.4991
O4-C3 1.4104,
C1-C2-C3 59.78

==> file2.txt <==
C2-C1 1.5052
C3-C2 1.505
C3-C1 1.5037
S4-C3 1.7976,
C1-C2-C3 59.95

Not the answer you're looking for? Browse other questions tagged or ask your own question.