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 pullmulticonfig: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) ... ???