Gary Barnes
Gary Barnes

Reputation: 73

Add a character to the next n nonempty lines after regex in bash

I have a configuration file that contains the following lines and want to know of a way to add a ';' at the beginning of each line following [treadmill] until the next blank line. I would like to do this from a script since these lines are to be included depending on the configuration of that 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

Upvotes: 3

Views: 101

Answers (3)

Gary Barnes
Gary Barnes

Reputation: 73

This is pretty convoluted however it does work.

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

Upvotes: 0

slitvinov
slitvinov

Reputation: 5768

With awk

awk '!NF { f = 0 }
         { print (f == 1 ? ";" : "") $0 }
     $0 ~ /^\[treadmill\]$/
         { f = 1 }
' file

Upvotes: 0

stevesliva
stevesliva

Reputation: 5665

sed -e '/\[treadmill\]/,/^$/{//!s/^/;/}' treadmill.txt

Explanation:

  • /\[treadmill\]/,/^$/ uses /START/,/END/ syntax to apply the subsequent commands in curly braces {} in the START to END range of lines, inclusive of the START and END lines. /^$/ requires an entirely empty line, no whitespace.

  • {//!s/^/;/} is one command in braces, applied within the above range.

  • //! means, "didn't match the previous match," as // is the previous match. This prevents the START and END lines from being processed

  • //!s/^/;/ chains the replacement s/^/;/ onto lines where //! is true. That adds a semicolon to each line between START and END

  • My initial suggestion for the semicolon addition was s/.*/;&/ - this replaces .* with ;& where & in the replacement side corresponds to whatever .* matched. As @WilliamPursell commented, this is potentially less clear than s/^/;/

  • In some shells, the ! is a special character that needs backslash escaping as well. It should be okay unescaped in bash.

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

Upvotes: 2

Related Questions