Reputation: 4531
I am trying bash scripting for the first time and I'm stuck on using sed
to alter a config file. The keys that I need to edit are pretty generic and used throughout the file, so I have to rely on a section to know where to do my "touching".
So, as said, there are multiple sections around the file, declared by [section name]
and then under it, you have the configurations for that section, indented by one tab. There are keys like enabled
, type
etc. which are used all over the file.
So a complete section would look like this:
[backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
So what I need to do is:
enabled = no
to enabled = yes
destination
's value to an IP address with a port (192.168.99.38:2003
)hostname
's value to another hostname, maybe the machine's hostname ($HOSTNAME
?).Thing is, I'm not sure how to tackle this at all. I have looked around for sed multiline handling, but I definitely don't know how to match the [backend]
section only. This is very new to me.
Upvotes: 0
Views: 121
Reputation: 23884
As you comment me: Only what's under [backend], nothing else
It may interest you doing that with Perl and if not just comment me; I will delete and the answer.
Say you have this file:
[no-backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
[backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
[no-backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
This one-liner finds that section for you:
perl -lne '$b=$.; $e=($b+10) if /\[backend\]/;print if $b++<$e' file
or readable version
perl -lne 'if( /\[backend\]/ ){ $b=$.; $e=( $b+10 ); }; if( $b++ < $e ){ print }' file
and the output:
[backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
and now instead of print you can modify that section with:
s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/$HOSTNAME/
the full one-liner
perl -lpe 'if(/\[backend\]/){$b=$.;$e=($b+10);};if($b++<$e){ s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/\$HOSTNAME/ }' file
and the output:
[no-backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
[backend]
enabled = yes
data source = average
type = graphite
destination = 192.168.99.38:2003
prefix = netdata
hostname = $HOSTNAME
update every = 10
buffer on failures = 10
timeout ms = 20000
[no-backend]
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = localhost
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
and finally after checking the output if everything was good, then you can use -i
option to use edit-in-place feature, like:
perl -i.bak -lne '...the rest of the script...' file
.bak is just for getting backup of your old file. ( like: file.txt.bak )
UPDATE for your comment
perl -lpe '$hn=qx(cat /etc/hostname);chomp $hn;if(/\[backend\]/){$b=$.;$e=($b+10);};if($b++<$e){s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/$hn/ }' file
and the output:
...
...
[backend]
enabled = yes
data source = average
type = graphite
destination = 192.168.99.38:2003
prefix = netdata
hostname = k-five
update every = 10
buffer on failures = 10
timeout ms = 20000
...
...
Upvotes: 1
Reputation: 12887
Assuming the text is in configfile and there is another section underneath starting with "[", the solution below should work
sed -i '/\[backend\]/,/\[/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
We search for the text between [backend] and [ and then execute the sed commands enclosed in {} We remove # and then edit the destination as well as finally the hostname.
If there are no other sections below backend, change the command to:
sed -i '/\[backend\]/,/^$/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
Upvotes: 1
Reputation: 3363
sed
is not the ideal tool for this kind of stuff, but it can be done:
/^\[.*]$/h
{G;/\n\[backend\]$/{
s/#//
/enabled/s/no/yes/
/destination/s/localhost/whatever/
/hostname/s/localhost/something else/
}
s/\n\[.*\]$//
}
Upvotes: 1