Reputation: 425
In linux, I see a lot of programs add things to my rc files between their own start and end delimiter patterns. For example, with conda:
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/tidu/miniconda3/bin/conda' 'shell.zsh' 'hook' 2>/dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/home/tidu/miniconda3/etc/profile.d/conda.sh" ]; then
. "/home/tidu/miniconda3/etc/profile.d/conda.sh"
else
export PATH="/home/tidu/miniconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
I want to do the same thing for some of my configs.
# dynamic start pattern
dynamic
body
# dynamic end pattern
dynamic means that the content may be generated dynamically, not hard coded in the script.
I tried a lot but is yet to find out a clean way to do this seemingly very common thing. Please show me how to do this with some commandline tools like awk
, sed
or perl
.
Upvotes: 0
Views: 58
Reputation: 29167
With all these utilities it is quite simple to cut the original file in 3 parts:
Replacing the middle part is then easy. Example with awk
, assuming the text to update is prepared in bash variable str
, and awk variables start
and end
contain the regular expressions that match the start and end delimiter lines:
# foo.awk
$0 ~ start {
if(n != 0) {
n = 3
exit
}
n = 1
}
n == 0 || n == 2 {
print
}
$0 ~ end {
if(n != 1) {
n = 3
exit
}
print str
n = 2
}
n == 1 {
next
}
END {
if(n != 0 && n != 2) {
print "error"
exit 1
} else if(n == 0) {
print str
}
}
$ start='# dynamic start pattern'
$ end='# dynamic end pattern'
$ str="\
$start
dynamic
body
$end"
$ awk -v str="$str" -v start="^$start\$" -v end="^$end\$" -f foo.awk foo.rc > new.rc
The most complicated part is detecting errors (start and end in reverse order, one start but no end, one end but no start, more than one start or end...) The n
awk variable is used to keep track of the current state: before start (n=0
), after end (n=2
), in between (n=1
) or error (n=3
). If an error occurs awk
exits with status 1. Else, if it exits with status 0, you can replace the old rc file by the new one.
Upvotes: 1