2

I'm trying to make a bash shell script that mounts, from some pre-obtained variables, a text file.

For this I use sed, changing the flags of the file by the desired:

sed "s/this is a line in text/$var/g" file

It works correctly and without problems. However, the $var variable often has strange characters, often being cryptographic keys such as:

-----BEGIN CERTIFICATE-----
MIID0DCCArigAwIBAgIJAMZxe+Z+DbdtMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV
BAYTAi0tMQswCQYDVQQIEwItLTELMAkGA1UEBxMCLS0xCzAJBgNVBAoTAi0tMRgw
FgYJKoZIhvcNAQkBFgltZUBteS5vcmcwHhcNMjEwODI1MDgyODMzWhcNMzEwODIz
MDgyODMzWjBOMQswCQYDVQQGEwItLTELMAkGA1UECBMCLS0xCzAJBgNVBAcTAi0t
MQswCQYDVQQKEwItLTEYMBYGCSqGSIb3DQEJARYJbWVAbXkub3JnMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1VtgDdOnhyGGd3OQO+QHcqfiH1wP1wJC
5MPZFm9FOQKC74FscbeLflu+hXVSLQQjP8XgJrbCk+xNe+SFOLMoIG mpxvRsjZU
eLzA5lUR8PvmBvgt1iR s1AQQAyh6R7z5QdwamsjmyoE1Si6maRzeCiv46qmlyet
iUEqbXslMk8N6Pa3KsKskv7BgzSOlfLHuWaZScewViGBSbyKUUYV0ljWbGozs21i
w FftSM6JnyNIq6l0wvGYkpJoDpGyxeNPTykswSO6WsG5o8ogJYOQR3KduUqdalj
tHbBsnGB1PNqfhpkBn75FY 8aNryND+uYkkQu1fGVJG0j2XVcPSPpBywZSwGtcCO
LPTL9OIYlRzzVi vTS CRx4NqSY=
-----END CERTIFICATE-----

When this happens, the sed command breaks, resulting in:

sed: -e expression #1, char 39: unterminated `s' command

I understand that the contents of the variable is interpreted by sed as part of the sed command, giving the error.

Is there a way to send the variable to sed as plain text and that it is not interpreted?if is not possible, is there any simple alternative to replace sed in this case?


Update with proof that the content of the certificate has the special character /.

cat ca.crt | grep "\/"

grep: warning: stray \ before / 5MPZFm9FOQKC74FscbeLflu+hXVSLQQjP8XgJrbCk+xNe+SFOLMoIG/mpxvRsjZU eLzA5lUR8PvmBvgt1iR/s1AQQAyh6R7z5QdwamsjmyoE1Si6maRzeCiv46qmlyet gUX/9Bunyu65hQ+h5kV4aWMRgnDH8HoTQsrJQd4eshHwsqgQA3+Oou4m6GLihkfC QwsENypmlOiOeYvmxBC0X/w/2IeZMEDbmrMO0yUL6No9xQan7wKNFwIDAQABo4Gw ggEBAJBDpHQBNlFoMjeQrH1szNe+30rp3ECCwXH4L+qKegobZ5/+joWSk84pRF0J w/FftSM6JnyNIq6l0wvGYkpJoDpGyxeNPTykswSO6WsG5o8ogJYOQR3KduUqdalj tHbBsnGB1PNqfhpkBn75FY/8aNryND+uYkkQu1fGVJG0j2XVcPSPpBywZSwGtcCO LPTL9OIYlRzzVi/vTS/CRx4NqSY=

3 Answers3

4

If we assume that the "this is a line in text" consists of one word, then we can use a macro processor:

m4 -Dword="$var" file

Where is "word" - A name is any sequence of letters, digits, and underscore, where the first character is not a digit.

nezabudka
  • 2,428
  • 6
  • 15
4

If you insert the contents of a file (not the value of a variable) with sed, it's easier:

sed -e '/^this is a line in text$/r mycert' -e '//d' file

This will parse the file called file. If a line which matches the expression ^this is a line in text$ is found, the file called mycert is inserted, without interpretation of any kind. The original line from file is then deleted.

You can get this to read from your variable like so:

printf '%s\n' "$var" |
sed -e '/^this is a line in text$/r /dev/stdin' -e '//d' file

Here, instead of reading from mycert when the line is found, sed will read from standard input, which is provided via printf. This assumes that the trigger line only occurs a single time in file.

Kusalananda
  • 333,661
2

In case of the certificate, there are only two problematic characters: a slash and newline. You can use parameter expansion to replace them by \/ and \n respectivelly which sed understands:

var=${var//$'\n'/\\n/}
var=${var//\//\\\/}
sed "s/text/$var/"

But in general, I'd use Perl which knows which characters come from a variable and what characters are part of the syntax:

var=$var perl -pe 's/text/$ENV{var}/'
choroba
  • 47,233