CarComp
CarComp

Reputation: 2016

Trying to write a heredoc into an existing file using Sed in bash

I'm attempting to write a heredoc at the top of my php.ini file directly under the [PHP] line. I'm also attempting to do it assuming the following conditions:

  1. [PHP] might not be at the very top (in other use cases, it would be nice to know how to put a heredoc anywhere in a file after something, so specifying 'line 2' isn't really useful
  2. The heredoc has to be contained in the file. No use of sed where another file is opened and read into the existing file
  3. Assume there is only one instance of the [PHP] identifier. In this learning exercise, I'm not worried about iterating a list, or Sed / Awk finding more than one instance of my search string
  4. I'd really like to have each item on its own line just like in the heredoc

Script:

myvar=$(cat << END_HEREDOC
[xdebug]
zend_extension=/usr/lib/php/20151226/xdebug.so
xdebug.remote_host = localhost
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.show_local_vars=0
xdebug.var_display_max_data=10000
xdebug.var_display_max_depth=20
xdebug.show_exception_trace=0
xdebug.remote_handler=dbgp
END_HEREDOC
)

echo ${myvar}

sed -i "/\[PHP\]'/${myvar}/'" php.ini

In every iteration I've tried, I simply end up with a php.ini looking like this:

[PHP]
$myvar

Or, I get the following error:

sed: -e expression #1, char 15: unknown command: `e'

My goal is:

[PHP]

[xdebug]
zend_extension=/usr/lib/php/20151226/xdebug.so
xdebug.remote_host = localhost
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.show_local_vars=0
xdebug.var_display_max_data=10000
xdebug.var_display_max_depth=20
xdebug.show_exception_trace=0
xdebug.remote_handler=dbgp

Upvotes: 1

Views: 1026

Answers (2)

Cole Tierney
Cole Tierney

Reputation: 10314

You can use the sed r command which inserts text from a file, but use process substitution to replace the filename with the heredoc:

#!/bin/bash

sed -i '' '/\[PHP]/r '<(cat << END_HEREDOC
[xdebug]
zend_extension=/usr/lib/php/20151226/xdebug.so
xdebug.remote_host = localhost
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.show_local_vars=0
xdebug.var_display_max_data=10000
xdebug.var_display_max_depth=20
xdebug.show_exception_trace=0
xdebug.remote_handler=dbgp
END_HEREDOC
) php.ini

Upvotes: 1

John1024
John1024

Reputation: 113844

While this task can be done with sed, sed is not optimal. It does not support variables. Anytime one has to encorporate shell variables within a sed command, one opens potential security flaws. Awk, by contrast, is well-suited to this task. If you have GNU awk (gawk), try:

$ cat script.sh
myvar='
[xdebug]
zend_extension=/usr/lib/php/20151226/xdebug.so
xdebug.remote_host = localhost
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.show_local_vars=0
xdebug.var_display_max_data=10000
xdebug.var_display_max_depth=20
xdebug.show_exception_trace=0
xdebug.remote_handler=dbgp
'
awk -i inplace -v x="$myvar" '{print} /\[PHP\]/{print x}' php.ini

The result is:

$ cat php.ini
[PHP]

[xdebug]
zend_extension=/usr/lib/php/20151226/xdebug.so
xdebug.remote_host = localhost
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.show_local_vars=0
xdebug.var_display_max_data=10000
xdebug.var_display_max_depth=20
xdebug.show_exception_trace=0
xdebug.remote_handler=dbgp

BSD/OSX or other non-GNU awk

If your awk does not support GNU's -i inplace option, then replace the awk line with:

awk -v x="$myvar" '{print} /\[PHP\]/{print x}' php.ini >tmp && mv tmp php.ini

Notes

myvar can be defined directly, as shown above, without using cat or here-docs.

Upvotes: 2

Related Questions