Skip to content
Advertisement

truncate shell command output from last line matching a string until EOF

I would like to truncate the output of a shell script and only print the part between the last line matching a string/regex and EOF.

E.g when running letsencrypt certbot renew --post-hook "service apache2 reload; service nginx reload" I get something like

...
http-01 challenge for domain1.tld
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/domain1.tld/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/domain2.tld
-------------------------------------------------------------------------------
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for domain.tld
http-01 challenge for www.domain2.tld
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/domain2.tld/fullchain.pem
-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/domain1.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain2.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain3.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain4.tld/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
Running post-hook command: service apache2 reload; service nginx reload
Output from service:
 * Reloading web server apache2
 * 
 * Reloading nginx configuration nginx
   ...done.

Now what I want to have is everything after the last ------- line, so the desired result would be

** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/domain1.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain2.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain3.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain4.tld/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
Running post-hook command: service apache2 reload; service nginx reload
Output from service:
 * Reloading web server apache2
 * 
 * Reloading nginx configuration nginx
   ...done.

I thought about some tail -n 15 command but I don’t want to adjust my script each time I add a new domain.

Thanks for your help!


Edit: In the meantime I found a solution on my own which is not as nice as @anubhava’s

cnt1=`grep -n "----" certbot.log | tail -n1 | awk -F : '{ print $1 }'`
cnt2=`wc -l certbot.log | awk '{ print $1 }'`
cnt3=$((cnt2-cnt1))
tail -n $cnt3 certbot.log

Advertisement

Answer

You can use awk for this:

awk '/^-{6}/{p=1; str=""; next} p{str = str $0 ORS} END{printf "%s", str}' file

This awk command matches ------ as starting text in any line and once it finds it we set a flag p to 1 and initialize a buffer str to empty. Next we keep adding each line into buffer str if flag p is set.

Note that if we encounter another ------ then we reinitialize str to empty hence keeping lines from only last matched occurrence.

Output:

** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/domain1.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain2.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain3.tld/fullchain.pem (success)
  /etc/letsencrypt/live/domain4.tld/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
Running post-hook command: service apache2 reload; service nginx reload
Output from service:
 * Reloading web server apache2
 *
 * Reloading nginx configuration nginx
   ...done.

Alternative solution is to use tac before and after awk and print only first match:

tac file | awk '/^-{6}/{exit} 1' | tac
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement