Add character on next n non-blank lines after regex in bash
I have a config file that contains the following lines and would like to know how to add ';' at the beginning of each line after the [treadmill] until the next blank line. I would like to do it with a script as these lines should be included depending on the configuration of this environment.
[treadmill]
type = aor
contact = server.domain.com
[A_SRV]
type = aor
contact = serverA.domain.com
[B_SRV]
type = aor
contact = serverB.domain.com
[treadmill]
type = identify
endpoint = treadmill
match = server.domain.com
[C_SRV_IDEN]
type = identify
endpoint = sip
match = server.domain.com
[treadmill]
type = endpoint
context = LocalSets
dtmf_mode = rfc4733
disallow = all
allow = ulaw
direct_media = no
aors = treadmill
source to share
sed -e '/\[treadmill\]/,/^$/{//!s/^/;/}' treadmill.txt
Explanation:
-
/\[treadmill\]/,/^$/
uses the syntax/START/,/END/
to apply subsequent commands in curly braces{}
in the range START to END, including the START and END lines./^$/
a completely empty string is required, no spaces. -
{//!s/^/;/}
- one command in curly braces applied in the above range. -
//!
means that "does not match the previous match" because it//
is a previous match. This prevents START and END lines from being processed. -
//!s/^/;/
binds the replacements/^/;/
to strings where//!
true. This adds a semicolon to every line between START and END -
My initial suggestion for a semicolon skeleton was
s/.*/;&/
- this replaces.*
with;&
, where&
on the replacement side matches any.*
. As @WilliamPursell commented, this is potentially less clear thans/^/;/
- In some shells, this
!
is a special character that also needs to be flushed back. In bash, it should be fine.
Output:
[treadmill]
;type = aor
;contact = server.domain.com
[A_SRV]
type = aor
contact = serverA.domain.com
[B_SRV]
type = aor
contact = serverB.domain.com
[treadmill]
;type = identify
;endpoint = treadmill
;match = server.domain.com
[C_SRV_IDEN]
type = identify
endpoint = sip
match = server.domain.com
[treadmill]
;type = endpoint
;context = LocalSets
;dtmf_mode = rfc4733
;disallow = all
;allow = ulaw
;direct_media = no
;aors = treadmill
source to share
It's pretty confusing, but it actually works.
grep -ne "^\[treadmill\]" $DIRPATH/pjsip.conf.sample | cut -d : -f 1 | awk '{print $1" on"}' > lines.txt
grep -n '^$' $DIRPATH/pjsip.conf.sample | cut -d : -f 1 | awk '{print $1" off"}' >> lines.txt
cat lines.txt | sort -n > lines2.txt
IFS=$'\n' # make newlines the only separator
declare -i arr4
items=0
for i in $(cat lines2.txt) ; do
SWITCH=`echo $i | cut -d' ' -f 2`
LINE=`echo $i | cut -d' ' -f 1`
if [ "$SWITCH" = "on" ] && [ $SWITCHED -eq 0 ]; then
SWITCHED=1
arr4[$items]=$LINE
((++items))
fi
if [ "$SWITCH" = "off" ] && [ $SWITCHED -eq 1 ]; then
SWITCHED=0
arr4[$items]=$LINE
((++items))
fi
done
count=${#arr4[@]}
let SECTIONS=$count/2
let SECTIONS-=1
for i in `seq 0 $SECTIONS` ; do
let START=$((arr4[$i*2]))
let END=$((arr4[($i*2)+1]))-1
for j in `seq ${START} ${END}` ; do
sed -i "$j s/^/;/" $DIRPATH/pjsip.conf.sample
done
done
rm lines.txt lines2.txt
source to share