-1

So i have the result of an API call to a file containing PEM certificates (many of them) like this:

-----BEGIN CERTIFICATE-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBB
-----END CERTIFICATE-----


-----BEGIN CERTIFICATE-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAssssssssssssssssssssssssssssssssssssssssssssss
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdddddd
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAssss
-----END CERTIFICATE-----

With the help @user2856925 answer here ( https://serverfault.com/a/718751 ) i got working my script that should get each certificate expiration date.

while read line
do
    if [ "${line//END}" != "$line" ]; then
        txt="$txt$line\n"
        printf -- "$txt" | openssl x509 -enddate -noout  | cut -d "=" -f 2
        txt=""
    else
        txt="$txt$line\n"
    fi
done < /path/to/bundle/file

Now while this thing does what I want it would be perfect to understand it so I can use it maybe in some other script.

Let's get to the questions then. What does "${line//END}" do ? what is // on a string, it is checking that the END word is contained by the variable line??!

I ran bash -x and saw the variable txt is being added the next line until the END CERTIFICATE is found then the printf line is run. So after this line txt="$txt$line\n" it goes back to the while?? That would explain the line txt="" which is emptying the variable so the next certificate is coming along.

But then why do we need the else txt="$txt$line\n"??

The script also ignores all those whitespaces 2 or more or no at all between the certificates or if the certificate is rightly formatted, it just works which is great, I'm not complaining but how does it do?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
trustbyte
  • 21
  • 1
  • 6
  • See [Shell Parameter Expansion](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion:~:text=%24%7Bparameter%2F&text=If%20pattern%20begins%20with%20%E2%80%98/%E2%80%99,%20all%20matches%20of%20pattern%20are%20replaced%20with%20string.). – oguz ismail Jun 29 '20 at 15:30

1 Answers1

0

DO a little basic testing.

$: line='-----END CERTIFICATE-----'
$: echo $line
-----END CERTIFICATE-----
$: echo "${line//END}"
----- CERTIFICATE-----

Using oguz ismail's excellent link from above -

The "${line//END}" is a string replacement, taking the value of $line and doing a rplacement of pattern with string.

Admittedly, manual pages can be a little obtuse. Basically, the structure is that inside the left/open curly, just after the name of the variable to be parsed, you put a slash to tell the parser that this is a pattern match/replace. Since the first field it the pattern to match/replace, and empty pattern typically makes no sense, so if the next character is also an unescaped slash, then it makes the scan global (it usually only applies to the first hit).

That means END is the search pattern. No replacement pattern is given, so none is used - it gets replaced with nothing.

[ "${line//END}" != "$line" ] then means "try to remove any occurrences of END, then see if anything changed." It works, but personally, I dislike this structure. You could just use a search --

if [[ "$line" =~ END ]] # check for END

but I'm fond of case statements.

while read line
do case "$line" in
   *END*) txt="$txt$line\n"
          printf -- "$txt" | openssl x509 -enddate -noout  | cut -d "=" -f 2
          txt=""
   ;;
   *) txt="$txt$line\n"
   ;;
   esac
done < /path/to/bundle/file

Will leave other tweaks as not what you asked. :)

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • 1
    i added some messages to your code to understand it better and it definitely clearer with a case statement. that $txt variable is getting filled on the catch all until the END line is find.thanks Paul! `while read line do case "$line" in *END*) echo "line at END ${line}" >> /tmp/1 txt="$txt$line\n" echo "txt at END ${txt}" >> /tmp/1 printf -- "$txt" | openssl x509 -enddate -noout | cut -d "=" -f 2 txt="" ;; *) echo "line at catch ${line}" >> /tmp/1 txt="$txt$line\n" echo "txt at catch ${txt}" >> /tmp/1 ;; esac done < /tmp/tmpf` – trustbyte Jun 29 '20 at 18:46
  • about the documentation, even after reading many times that ${parameter/pattern/string} part how in the world someone could have thought of using it that way... it is interesting how it is being used to parse that huge file and does not bother to look for the BEGIN part but only to look out for the END and the check the certificate composed of all the lines previously added to that variable. now an educatiing exercise for me would be to use an array instead of a file as source to see if i can make it work. – trustbyte Jun 29 '20 at 18:54
  • There are a lot of things I'd tweak, but I'm ADHD/OCD, LOL. Still, since they are emptying `$txt` each time, it works out the same. – Paul Hodges Jun 30 '20 at 14:27