Home > database >  Sed dynamically search for string with and without ' ' character
Sed dynamically search for string with and without ' ' character

Time:03-17

So I have a configuration file that is parsed by various scripts, therefore the format can't be changed, although the contents can as long as the format is being strictly followed. This file by default contains strings such as

multiconfig:nmb-devel:nmb-trs-devel
multiconfig:nmb-deploy:nmb-trs-deploy
multiconfig:nmb-deploy:nmb-trs-deploy 

multiconfig:ijk-devel:ijk-trs-devel
multiconfig:ijk-deploy:ijk-trs-deploy
multiconfig:ijk-deploy:ijk-trs-deploy 

multiconfig:qrs-devel:qrs-trs-devel
multiconfig:qrs-deploy:qrs-trs-deploy
multiconfig:qrs-deploy:qrs-trs-deploy 

Currently, I have a script that parses these configurations (multiconfig:...) into an array, as well as an array of configurations to replace these original configurations. e.g.

TARGETS="multiconfig:new-devel:new-trs-devel multiconfig:newer-devel:newer-trs-devel multiconfig:newest-devel:newest-trs-devel"
NEW_TARGETS_ARR=( $TARGETS )
OLD_TARGETS_ARR=($(sed -n '/multiconfig/p' conf.txt | tail -n  2 | awk '!seen[$0]  '))

Note: Not the sed operation in question

These work fine, and result in proper arrays such as:

NEW_TARGETS_ARR: multiconfig:new-devel:new-trs-devel, multiconfig:newer-devel:newer-trs-devel, multiconfig:newest-devel:newest-trs-devel

OLD_TARGETS_ARR: multiconfig:nmb-devel:nmb-trs-devel, multiconfig:nmb-deploy:nmb-trs-deploy, multiconfig:nmb-deploy:nmb-trs-deploy , multiconfig:ijk-devel:ijk-trs-devel, multiconfig:ijk-deploy:ijk-trs-deploy, multiconfig:ijk-deploy:ijk-trs-deploy , multiconfig:qrs-devel:qrs-trs-devel, multiconfig:qrs-deploy:qrs-trs-deploy, multiconfig:qrs-deploy:qrs-trs-deploy

My objective is to replace the old configurations by the new configurations.

My method of doing this right now is by looping through the OLD_TARGETS_ARR and replacing each OLD_TARGETS_ARR[index] with the NEW_TARGETS_ARR[index] as such:

for i in ${!OLD_TARGETS_ARR[@]}
do
        if [ "${NEW_TARGETS_ARR[$i]}" = "" ]; then
                NEW_TARGETS_ARR[$i]="[EMPTY]"
        fi


        echo $i
        echo "OLD TARGET $i: ${OLD_TARGETS_ARR[$i]}"
        echo "NEW TARGET $i: ${NEW_TARGETS_ARR[$i]}"
        echo "sed -i \"s/${OLD_TARGETS_ARR[$i]}/${NEW_TARGETS_ARR[$i]}/g\" conf.txt"
        sed -i "s/${OLD_TARGETS_ARR[$i]}/${NEW_TARGETS_ARR[$i]}/g" conf.txt
done

Now, theoretically what this should (or what I want) result in is as follows

conf.txt

multiconfig:new-devel:new-trs-devel
multiconfig:newer-devel:newer-trs-devel
multiconfig:newest-devel:newest-trs-devel

[EMPTY]
[EMPTY]
[EMPTY]

[EMPTY]
[EMPTY]
[EMPTY]

Although what this actually results in is as follows

conf.txt

multiconfig:new-devel:new-trs-devel
[EMPTY]
[EMPTY] 

[EMPTY]
[EMPTY]
[EMPTY] 

[EMPTY]
[EMPTY]
[EMPTY] 

While I haven't figured out why more entries than are necessary are getting replaced with '[EMPTY]', I have figured out that on the ' ' on 'deploy ' is not getting parsed, and must be escaped in some way, shape, or form. Given that these sed operations are dynamic, I can't simply add a \ in front of the ' '. First, how could I ensure that the ' ' is getting parsed as part of the string to search for in the sed operation?

Second, I probably am misunderstanding some basic part of sed, or my loop, although why is everything except for the first match getting replaced with '[EMPTY]'?

I appreciate any input anyone can give,

thank you all in advance!

CodePudding user response:

Assuming you are trying to match nmb, using your NEW_TARGETS array, you could try this implementation

#!/usr/bin/env bash

NEW_TARGETS=(multiconfig:new-devel:new-trs-devel multiconfig:newer-devel:newer-trs-devel multiconfig:newest-devel:newest-trs-devel)

i=0
while read -r line; do 
    sed "/^multiconfig:nmb/s/.*/${NEW_TARGETS[$i]}/;/new\|^$/! c\[EMPTY]" <<< $line
    i=$((i 1))
done < input_file

OUTPUT

multiconfig:new-devel:new-trs-devel
multiconfig:newer-devel:newer-trs-devel
multiconfig:newest-devel:newest-trs-devel

[EMPTY]
[EMPTY]
[EMPTY]

[EMPTY]
[EMPTY]
[EMPTY]

CodePudding user response:

A small change to OP's current code:

  • enable regex matching (-E)
  • terminate the search pattern with 0 or more spaces followed by EOL ($)

Rolling this into OP's current code:

for i in ${!OLD_TARGETS_ARR[@]}
do
        if [ "${NEW_TARGETS_ARR[$i]}" = "" ]; then
                NEW_TARGETS_ARR[$i]="[EMPTY]"
        fi
        sed -iE "s/${OLD_TARGETS_ARR[$i]}[[:space:]]*$/${NEW_TARGETS_ARR[$i]}/" conf.txt
done

This generates:

$ cat conf.txt
multiconfig:nmb-devel:nmb-trs-devel
multiconfig:new-devel:new-trs-devel
multiconfig:newer-devel:newer-trs-devel

multiconfig:newest-devel:newest-trs-devel
[EMPTY]
[EMPTY]

[EMPTY]
[EMPTY]
[EMPTY]

NOTE:

  • this differs from OP's expected output but I can't tell if this was a typo by OP
  • OP states there's nothing wrong with the OLD_TARGETS_ARR/sed/tail operation but ...
  • it's this tail operation that fails to pull multiconfig:nmb-devel:nmb-trs-devel into the arrays
  • this in turn throws off the replacements when the only thing being used to 'match' the old and new lines is the numeric index of the array
  • I'm guessing OP probably wants a different design that performs the matching based on actual strings (eg, HatLess' answer) ... ???
  • Related