0

There are several answers on this site about how to capture text between two patterns and print out each group, but I am interested only in the last group. I am doing this on Mac, not Linux.

My output comes from echo "" | openssl s_client -showcerts -connect oidc.eks.us-east-1.amazonaws.com:443 2>&1 |\ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;/-END CERTIFICATE-/a\' and I want to grab the last cert, between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- inclusive.

To generalize, in text like

start
a
b
c
end
start
d
e
f
end
start
g
h
i
end

how can I just get

start
g
h
i
end

The reason I need this is because I need to get the last cert in a chain to get its thumbprint via openssl x509 -fingerprint -noout to create an AWS OIDC provider programatically.

swagrov
  • 1,510
  • 3
  • 22
  • 38
  • Always important to mention: [Is a /start/,/end/ range expression ever useful in awk?](https://stackoverflow.com/questions/23934486/is-a-start-end-range-expression-ever-useful-in-awk) – kvantour Jan 24 '20 at 11:00

4 Answers4

3
$ awk '/start/{rec=""; f=1} f{rec=rec $0 ORS} /end/{f=0} END{printf "%s", rec}' file
start
g
h
i
end
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Could you please try following tac + awk solution.

tac Input_file | awk '/end/,/start/{print;if($0=="start"){exit}}' | tac

OR as per Ed sir's comments more concise solution will be:

tac Input_file | awk '/end/{f=1} f; /start/{exit}' | tac

Solution with detailed explanation:

tac Input_file |            ##Print Input_file in reverse style, from bottom to top.
awk '                       ##Starting awk program from here.
  /end/,/start/{            ##Printing from range starting from end to start here.
    print
    if($0=="start"){        ##Checking if current line is start then exit from awk program.
      exit
    }
  }
' |                         ##Sending awk output to next command. 
tac

Output will be as follows.

start
g
h
i
end
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • The `awk` function does not work for me. I did this command and it just printed out the whole thing. (tail -r is the same as cat) echo "" | openssl s_client -showcerts -connect oidc.eks.us-east-1.amazonaws.com:443 2>&1 |\ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;/-END CERTIFICATE-/a\' | tail -r |\ awk '/-END CERTIFICATE-/,/-BEGIN CERTIFICATE-/{print;if($0=="start"){exit}}' | tail -r – swagrov Jan 24 '20 at 02:51
  • @swagrov, is it giving any error to you? Because when I tested it on bash it worked fine only – RavinderSingh13 Jan 24 '20 at 02:56
  • There is no error. I think the issue might be that the strings are `-----BEING CERTIFICATE-----` and `-----END CERTIFICATE-----`, not just `start` and `end`, so maybe that's the issue. I just tested your command with my example and it worked. Perhaps I should have explicitly use those strings. EDIT: I made a typo, see my final comment. – swagrov Jan 24 '20 at 03:01
  • @swagrov, what I am doing is to make calculation easy for awk I read reverse file so in spite of giving `/start/,/end/` give like `/end/,/start/` and it should fly then. Lemme know. – RavinderSingh13 Jan 24 '20 at 03:03
  • 1
    Your example works. It turns out I made a typo. Marking it as the answer. Thank you! – swagrov Jan 24 '20 at 03:04
1

I got this functioning like this:

echo "" | openssl s_client -showcerts -connect oidc.eks.us-east-1.amazonaws.com:443 2>&1 |\
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;/-END CERTIFICATE-/a\' | tail -r |\
sed -n '1,/-BEGIN CERTIFICATE-/ p' | tail -r

tail -r is very useful for this.

swagrov
  • 1,510
  • 3
  • 22
  • 38
0

Insert zero byte before each start. After that print last "line", where lines are separated by zero bytes.

sed 's/start/\x00&/` | tail -z -n1
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 2
    I should have mentioned that I am doing this on mac, and mac `tail` does not have the -z option like linux does. – swagrov Jan 24 '20 at 02:48