I would like to combine VPN certificates into a single file. This is a template file:

# some unrelated stuff 

ca ca.crt

# other unrelated stuff

And I want to replace line ca ca.crt with the following content:

# ca.crt contents

I tried this script:

cat client-template.ovpn | 
sed -e 's/ca ca.crt/<ca>\n<\/ca>/' | 
sed -e '/<ca>/r ca.crt'

Although this script works fine, I have to paste two other files along with ca.crt, and I would like to know, is there any command, which allows to combine both s and r commands together?

I am using sed, but answers with other Unix tools are welcome.


With good old ed:

ed -s client-template.ovpn <<\IN
/ca ca.crt/s//<ca>\
- r ca.crt
/cert client.crt/s//<cert>\
- r client.crt
/key client.key/s//<key>\
- r client.key

this changes a line like

tag tag.extension



and then reads in the content of tag.extension before (-) the closing tag line (i.e. the current line after the substitution). Replace ,p with w to actually write the changes to your template file (or use w somefile to save changes to another file). Keep in mind though that ed will error out if a pattern is not found.

With sed you could combine r with a (a, like r, does not operate on pattern space - unlike s which does):

sed '
/ca ca.crt/{
r ca.crt
/cert client.crt/{
r client.crt
/key client.key/{
r client.key
' client-template.ovpn

With GNU sed, assuming those ca file name don't contain single quote characters, you could do:

sed "s|^ca \(.*\)|echo '<ca>'; cat '\1'; echo '</ca>'|e"

For this problem I would not use sed, but use the approach mentioned in this thread - https://serverfault.com/questions/287688/templating-with-linux-in-a-shell-script

The idea is to use bash itself as the templating language, so you can easily do things like include files in your template.

Your template thus becomes a bash script that you run to generate your file. Applying it to your problem might look something like this:



cat <<-EOF
# some unrelated stuff

$(cat ca.crt)

$(cat other.file)

# other unrelated stuff

Usage from command-line:

$ make-client.sh > client.ovpn
  • I thought about this approach, however, I wouldn't like to modify the template config. It was generated by OpenVPN and I would like to take it as is. Thank you for the answer, though! – awesoon Sep 20 '15 at 10:19
sed -e 's/ca cert.crt/<ca>/' -e 'T' -e 'r cert.crt' -e 'a\</ca>' client-template.ovpn
  • Does not work, unfortunately, this script replaces ca cert.crt with <ca> \n ca cert.crt \n</ca> \n *file content*. I want to place the content inside <ca> tag. I also have a type in the question: not ca cert.crt but ca ca.crt. Could you, please, fix this in your answer in order to make posts more consistent? – awesoon Sep 20 '15 at 9:11
  • @soon See edited – Costas Sep 20 '15 at 18:47

If I understand your question correctly, it seems to be possible using a combination of r and D e.g.

sed '/^ca ca.crt/ {
r new-content-file
}' client-template.ovpn
  • 1
    Not exactly so. ca ca.crt should be replaced with <ca> *here the ca.crt content* </ca>. I could achieve this using two commands, as I noted at the end of the question, however, I am looking for a single command, since writing similar code for three files (I have to paste ca.crt, client.crt and client.key contents into <ca>, <cert> and <key> respectively) seems graceless for me. – awesoon Sep 20 '15 at 13:04
  • @soon sorry - I still don't see the distinction. Perhaps you should edit your question to include the additional requirement(s) more clearly i.e. examples of all 3 files and the full desired output. Is it simply a matter of adding a further two r commands? – steeldriver Sep 20 '15 at 13:10

If I understand correctly, you'd like to support a variable file name after the word ca. While you can do it with GNU sed, I'd use awk (or Perl).

awk '
    $1 == "ca" && NR == 2 { # if the current line consists of two words, the first of which is "ca"
        print "<ca>";
        while (getline <$2) print;
        print "</ca>";
    1    # print anything else unmodified
sed '5 i\
     5 r tempo.csv
     5 a\
     5 d' client-template.ovpn 
  • order of action is important (especially the d as last action
  • new line is represented by a ending \ in insert and append action
  • Not sure, if I understand your answer correctly, but will it paste the content of ca.crt file to the client-template.ovpn? – awesoon Sep 21 '15 at 8:18
  • adapted the reply for a generic file and surrounding value – NeronLeVelu Sep 21 '15 at 8:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.