1

I am relatively new to bash text editing commands and am trying to improve my skills so please bear with me!

I'm looking to write a simple command sequence for locating all SSL certificates on my platform and my ideal output would be three columns for the path, the filename and the expiry.

OK so far I have something like this:

sudo find / -type f \( \( -name "*.pem" -o -name "*.crt" \) ! -path "/unwanted/search/location/*" \) -exec sh -c 'echo {}; true' \; -exec openssl x509 -enddate -noout -in {} \; | sed s/notAfter=// | sed -r 's:/([a-Z0-9._-]*)$:\r\n\1:' | sed 's/GMT/&\n/'

This produces a usable output (am took me some fiddling to get functional). Here is some example output:

/etc/pki/tls/certs
gogs.crt
Feb  8 23:59:59 2018 GMT

/etc/pki/tls/certs
sample.crt
Jan 18 23:59:59 2018 GMT

Finally its question time - what tools should i leverage to reformat that to the following:

/etc/pki/tls/certs  gogs.crt   Feb  8 23:59:59 2018 GMT
/etc/pki/tls/certs  sample.crt Jan 18 23:59:59 2018 GMT

Straight columns are ideal, but not my initial goal - for now I really just wanted to understand how to improve my stream processing skills, surely there must be a way of stating:

Use output from last command, collapse the line breaks, replace with "tab", add linefeed, move onto next.

Is anyone able to offer some advice? Attempts to date have caused some nightmarish output - i would add an example if that wasn't going to add to the confusion!

Thanks readers!

3 Answers 3

3

You can modify like below inside -exec sh -c ' .... '

-exec sh -c 'file="${0##*/}"; path="${0%/*}"; expiry=$(openssl x509 -enddate -noout -in "$0" | sed "s/notAfter=//");  echo "$path $file $expiry"' {} \;
  • file="${0##*/}"; - Get filename

  • path="${0%/*}"; - Get path

  • expiry=$(openssl x509 -enddate -noout -in "$0" | sed "s/notAfter=//"); - Get expiry date

  • echo "$path $file $expiry" - print all variable at the end

It will become :

sudo find / -type f \( \( -name "*.pem" -o -name "*.crt" \) ! -path "/unwanted/search/location/*" \) -exec sh -c 'file="${0##*/}"; path="${0%/*}"; expiry=$(openssl x509 -enddate -noout -in "$0" | sed "s/notAfter=//");  echo "$path $file $expiry"  ' {} \;
Sign up to request clarification or add additional context in comments.

6 Comments

Side note: I'm not 100% sure where I have this from, but afair $0 is not guaranteed to work like this. Usually you'll use a trick like this: -exec bash -c '...' -- {} \; and then access the filename as $1. ($0 would be -- in that case)
From bash manual: A positional parameter is a parameter denoted by one or more digits, other than the single digit 0
@hek2mgl: Thanks so much, but I am bit confused personally, from man sh -c string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0 , man7.org/linux/man-pages/man1/sh.1p.html, and I tested few files on centos 6
This solution, with "| column -t" appended has given me exactly what i hoped for - thank you so much!
@AkshayHegde I totally understand your confusion. I'm confused too. Plus all currently known shells seem to support your code. But POSIX at least recommends to keep the first param (which ends in $0) for the command name. pubs.opengroup.org/onlinepubs/009695399/utilities/sh.html
|
3

The following precisely does what you asked for (Use output from last command, collapse the line breaks, replace with "tab", add linefeed, move onto next.):

awk -v RS= -F'\n' -v OFS='\t' '{$1=$1}1'

but adding yet another command to your pipeline isn't a great approach vs just using one script to do it all. If you ask a new question and post the output of the part of your script before the seds pipeline (i.e. the input to sed s/notAfter=// | sed -r 's:/([a-Z0-9._-]*)$:\r\n\1:' | sed 's/GMT/&\n/) as sample input and the expected output you want after processing that input then I'm sure someone can help you with that.

1 Comment

thank you for your advice - i'll need some time to research how awk interprets your instruction but its certainly doing the trick. Very much appreciate your time and advice!
1
your command|awk 'NF{ORS=(NR%3?FS:RS);print}'|column -t

4 Comments

why do you use awk twice?
This works really great, thank you. I'll have to find some time to properly parse what you've written before I can claim to understand it but the output is ideal.
In addition to @hek2mgls point, you asked for a command that produced tab-separated output and the above does not produce tab-separated output so how can it work really great? It will also fail when your file names contain spaces.
I agree that the solution is not ideal, and thanks for pointing out when it would fail. I'm still struggling to interpret it though - it feels hacky even though i don't know what i'm looking at!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.