0

I want to use awk for printing a match of some pattern, only if it is the last line of the file before some constant text.

For example, i want to print the value of "c" only if it is the last line before some constant text:

cat file.txt:
a=1
b=2
c=3
...constant text...

print 3.

cat file.txt:
a=1
c=3
b=2
...constant text...

do not print anything.

How do I do that..? How can awk know if it's the last number of the file?

  • 2
    awk -F'=' 'END{if ($1=="c") print $2} – Costas Feb 9 '15 at 17:50
  • Nice. But I'll edit my question. I need to know what line number relative to the end of the file I am... Because if I add some conant test to the file, like a comment, this will not work. – csny Feb 9 '15 at 18:04
  • @csny and how do you define "constant text"? What is a difference w.r.t. other lines in the file? – jimmij Feb 9 '15 at 18:10
  • '/...constant text.../{if (Prev[$1]=="c") print Prev[$2]}{split($0,Prev)}' – Costas Feb 9 '15 at 18:23
  • 1
    @csny This awk -F'=' '/...constant text.../{if (Prev[1]=="c") print Prev[2]}{split($0,Prev)}'? – Costas Feb 10 '15 at 9:20
3

I want to use awk for printing a match of some pattern, only if it is the last line of the file before some constant text.

In that case, try this:

awk -F= '/constant text/ && name=="c"{print value} {name=$1;value=$2}' file

Examples

$ cat file1 
a=1
b=2
c=3
...constant text...
$ awk -F= '/constant text/ && name=="c"{print value} {name=$1;value=$2}' file1
3
$ cat file2
a=1
c=3
b=2
...constant text...
$ awk -F= '/constant text/ && name=="c"{print value} {name=$1;value=$2}' file2
$ 

How it works

  • -F=

    This tells awk to use = as the field separator. In this way, we can separate the name and value for fields like a=1 or c=3.

  • /constant text/ && name=="c"{print value}

    If we reach a line with constant text and name (as last set on the previous line) is c, then print value.

  • name=$1;value=$2

    For the current line, save the first field as name and the second field as value.

1

If you don't mind using grep it has an option to print lines before match.

Option is : -B num, --before-context=num

In your case :

cat file.txt|grep -B 1 "constant text"|grep "c="|cut -f2 -d'='

Explanation :

  1. Print just the line before constant text.
  2. Filter all c values from output.
  3. Extract second field with '=' delimiter.
0

Some googling found me the best answer so far, though I already got an answer: Using tac makes it much simpler...

tac file | awk 'NR==2{if ( $1=="c") print $2}'

The line number is one after the "constant text". If the "constant text" is one line - NR==2. If it is two lines - NR==3. Haven't decided yet what format the constant text should be...

  • To continue your decision I'd like to offer use tail -n 2 instead of output reversing. – Costas Feb 10 '15 at 10:59
  • do you mean tail -2 file | head -1 and test for "c=..."? – csny Feb 10 '15 at 11:23
  • You are free to omit head by awk 'NR==1' – Costas Feb 10 '15 at 11:31
  • I actually tested for performance the two options: tail -2 ./test.txt | head -1 | grep "c=" | cut -d= -f2 vs tail -2 ./test.txt | awk -F'=' 'NR==1{if ( $1=="c") print $2}'. The awk` one is faster. Surprised and impressed. – csny Feb 10 '15 at 12:12
  • Check tail -2 ./test.txt | grep -m1 -Po '^c=\K.*' or | sed -n '1{/^c=/s///p;q}' – Costas Feb 10 '15 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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