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?

10
  • 2
    awk -F'=' 'END{if ($1=="c") print $2}
    – Costas
    Commented Feb 9, 2015 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
    Commented Feb 9, 2015 at 18:04
  • @csny and how do you define "constant text"? What is a difference w.r.t. other lines in the file?
    – jimmij
    Commented Feb 9, 2015 at 18:10
  • '/...constant text.../{if (Prev[$1]=="c") print Prev[$2]}{split($0,Prev)}'
    – Costas
    Commented Feb 9, 2015 at 18:23
  • 1
    @csny This awk -F'=' '/...constant text.../{if (Prev[1]=="c") print Prev[2]}{split($0,Prev)}'?
    – Costas
    Commented Feb 10, 2015 at 9:20

3 Answers 3

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...

8
  • To continue your decision I'd like to offer use tail -n 2 instead of output reversing.
    – Costas
    Commented Feb 10, 2015 at 10:59
  • do you mean tail -2 file | head -1 and test for "c=..."?
    – csny
    Commented Feb 10, 2015 at 11:23
  • You are free to omit head by awk 'NR==1'
    – Costas
    Commented Feb 10, 2015 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
    Commented Feb 10, 2015 at 12:12
  • Check tail -2 ./test.txt | grep -m1 -Po '^c=\K.*' or | sed -n '1{/^c=/s///p;q}'
    – Costas
    Commented Feb 10, 2015 at 13:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .