I resorted to discretizing portions of the blockrep.sed script to see if I could identify a source of breakdown. While that made no logical difference on the surface, that did create a functional and well-formed structure ... which did create a usable custom.sed, but only after I removed the --debug option for the execution of blockrep.sed. That is required because the degug info is not sent to the stderr, but is inline with the stdout !!! I don't know enought to classify that as a bug.
NOTE: I've also added command-line options to specify names of files for input, output, old_pattern, new_pattern, divider, among others.
The now modified and working version of the script is as follows:
#!/bin/bash
reportFiles ()
{
ls -l "${fileSrchPat}" "${fileReplPat}" "findrep.txt" 2>&1
ls -l "blockrep.sed" "custom.sed" "custom.err" 2>&1
ls -l "${fileBefore}" 2>&1
ls -l "${fileOutput}" 2>&1
}
DBG=0
DBGs=0
dumA=1 ;
dumB=1 ;
fileSrchPat=""
fileReplPat=""
divider="----REPLACE_BY----"
doReview=0
fileBefore=""
fileOutput=""
while [ $# -gt 0 ]
do
case $1 in
--debug )
DBG=1 ;
shift ;;
--debug_sed )
DBGs=1 ;
shift ;;
--verbose )
set -x
shift ;;
--old_pattern )
dumA=0 ;
fileSrchPat="$2" ;
if [ ! -s "${fileSrchPat}" ]
then
echo -e "\n File '${fileSrchPat}' not found.\n Bye!\n"
exit 1
fi ;
shift ; shift ;;
--new_pattern )
dumA=0 ;
fileReplPat="$2" ;
if [ ! -s "${fileReplPat}" ]
then
echo -e "\n File '${fileReplPat}' not found.\n Bye!\n"
exit 1
fi ;
shift ; shift ;;
--pattern_sep )
divider="$2" ;
shift ; shift ;;
--input )
dumB=0 ;
fileBefore="$2" ;
if [ ! -s "${fileBefore}" ]
then
echo -e "\n File '${fileBefore}' not found.\n Bye!\n"
exit 1
fi ;
shift ; shift ;;
--output )
fileOutput="$2" ;
if [ ! -s "${fileOutput}" ]
then
echo -e "\n File '${fileOutput}' already exists. Overwrite ? [y|N] => \c"
read goAhead
if [ -z "${goAhead}" ] ; then goAhead="N" ; fi
case ${goAhead} in
y* | Y* ) rm -vf "${fileOutput}" ;;
* ) echo -e "\n\t Process abandonned.\n Bye!\n" ; exit 1 ;;
esac
exit 1
fi ;
shift ; shift ;;
--review ) doReview=1 ; shift ;;
* ) echo "\n invalid option used on command line. Only valid options: [ --old_pattern {textfile1} | --new_pattern {textfile2} ] \n Bye!\n" ; exit 1 ;;
esac
done
###
### Code segment to be replaced
###
if [ -z "${fileSrchPat}" ]
then
fileSrchPat="File1.cpp"
rm -f "${fileSrchPat}"
cat >"${fileSrchPat}" <<"EnDoFiNpUt"
void Component::initialize()
{
my_component = new ComponentClass();
}
EnDoFiNpUt
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 1"
###
### Code segment to be used as replacement
###
if [ -z "${fileReplPat}" ]
then
fileReplPat="File2.cpp"
rm -f "${fileReplPat}"
cat >"${fileReplPat}" <<"EnDoFiNpUt"
void Component::initialize()
{
if (doInit)
{
my_component = new ComponentClass();
}
else
{
my_component.ptr = null;
}
}
EnDoFiNpUt
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 2"
if [ -z "${fileBefore}" ]
then
###
### Create demo input file
###
fileBefore="Test_INPUT.cpp"
rm -f "${fileBefore}"
{
echo "
other code1()
{
doing other things
doing more things
doing extra things
}
"
cat "${fileSrchPat}"
echo "
other code2()
{
creating other things
creating more things
creating extra things
}
"
} >>"${fileBefore}"
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 3"
###
### Create editing specification file
###
{
cat "${fileSrchPat}"
echo "${divider}"
cat "${fileReplPat}"
} >findrep.txt
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 4"
###
### sed script to create editing instructions to apply above editing specification file
###
test ${DBG} -eq 1 && rm -fv "blockrep.sed" || rm -f "blockrep.sed"
cat >"blockrep.sed" <<"EnDoFiNpUt"
#SOURCE: https://www.linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/sedfaq4_013.html
#
# filename: blockrep.sed
# author: Paolo Bonzini
#
# Modified by: Eric Marceau, Feb 2023
#
# Requires:
# (1) blocks to find and replace, e.g., findrep.txt
# (2) an input file to be changed, input.file
#
# blockrep.sed creates a second sed script, custom.sed,
# to find the lines above the row of 4 hyphens, globally
# replacing them with the lower block of text. GNU sed
# is recommended but not required for this script.
#
# Loop on the first part, accumulating the `from' text
# into the hold space.
#
##############################################################################
### Reworked Discretized version of coding
##############################################################################
#
##############################################################################
### Begin of capture - SEARCH pattern
##############################################################################
:markerA
EnDoFiNpUt
#echo "/^----REPLACE_BY----\$/! {" >> "blockrep.sed"
echo "/^${divider}\$/! {" >> "blockrep.sed"
cat >>"blockrep.sed" <<"EnDoFiNpUt"
#
# Escape slashes
s,[/],\\&,g
#
# Escape backslashes
s,[\],\\&,g
#
# Escape regular expression metacharacters
s,[[],\\&,g
s,[.],\\&,g
s,[*],\\&,g
#
# Escape the final newline
# add backslash to end of line (to avoid having sed
# think of as end of command input)
s,$,\\,
#
# APPEND - PATTERN space to HOLD space
H
#
# Sequence to APPEND "N" cmds needed to maintain the sliding window.
# \\ swap contents - HOLD and PATTERN space
x
#
# If first line, begin constructing sed command for pattern match and replace
1 s,^.,s/,
#
# If not first line, add line with "N"
# i.e. give instruction to "APPEND the next line of input into the pattern space"
1! s,^,N\
,
# // swap contents again - HOLD and PATTERN space
x
#
# COPY - next line of input into PATTERN space
n
#
# branch/jump to label markerA
b markerA
}
#
##############################################################################
### End of capture - SEARCH pattern
##############################################################################
#
#
##############################################################################
### Begin of capture - REPLACEMENT pattern
##############################################################################
#
# \\ swap contents - HOLD and PATTERN space
x
#
# Change the final backslash to a slash to separate the
# two sides of the s command.
s,\\$,/,
#
# // swap contents again - HOLD and PATTERN space
x
#
# Until EOF, gather the REPLACEMENT TEXT into the hold space.
:markerB
n
#
# Escape slashes
s,[/],\\&,g
#
# Escape backslashes
s,[\],\\&,g
#
# If not last line, add backslash to escape all instances of "$".
$! s,$,\\,
#
# APPEND - PATTERN space to HOLD space
H
#
# If not last line, branch/jump to markerB
$! b markerB
#
##############################################################################
### End of capture - SEARCH pattern
##############################################################################
#
#
# Start the Right-Hand Side (RHS) of the "s" command without a leading newline,
# add the P/D pair for the sliding window, and
# print the script.
#
# COPY - HOLD space to PATTERN space
g
s,/\n,/,
#
# (P) Print up to the first embedded newline of the current pattern space.
# then
# (D) If pattern space contains no newline, start a normal new cycle as if
# the d command was issued. Otherwise, delete text in the pattern space
# up to the first newline, and restart cycle with the resultant pattern space,
# without reading a new line of input.
# then
# (p) Print the current pattern space.
s,$,/\
P\
D,p
#---end of script---
EnDoFiNpUt
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 5"
test ${DBG} -eq 1 && rm -fv custom.sed custom.err || rm -f custom.sed custom.err
if [ ${DBGs} -eq 1 ]
then
echo -e "\n\t NOTE: debug mode active for 'sed' command ..."
sed --debug -f blockrep.sed findrep.txt >custom.sed 2>custom.err
else
sed -nf blockrep.sed findrep.txt >custom.sed 2>custom.err
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 6"
if [ -s custom.err ]
then
if [ ${doReview} -eq 1 ]
then
cat custom.err
fi
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 7"
if [ -s custom.sed ]
then
if [ ${doReview} -eq 1 ]
then
more custom.sed
echo -e "\n\t Hit return to continue ..." >&2
read k <&2
fi
if [ ${DBGs} -eq 1 ]
then
more custom.sed
echo -e "\n ============= End of Review - 'custom.sed' containing execution debug reporting =============" >&2
echo -e "\n\t 'custom.sed' is not in usable form due to '--debug' messaging." >&2
echo -e "\t Abandoning before attempting final transformation.\n Bye!\n" >&2
exit 2
fi
else
echo -e "\t Failed to create 'custom.sed'. Unable to proceed!\n" >&2
exit 1
fi
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 8"
if [ -z "${fileOutput}" ]
then
fileOutput="Test_OUTPUT.cpp"
fi
rm -f "${fileOutput}"
sed -f custom.sed "${fileBefore}" >"${fileOutput}"
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 9"
if [ -s "${fileOutput}" ]
then
test ${DBG} -eq 1 && echo -e "\n\t ======== fence 10"
if [ ${doReview} -eq 1 ]
then
more "${fileOutput}"
fi
if [ ${DBG} -eq 1 ]
then
reportFiles
if [ ${dumA} -eq 1 ]
then
rm -fv "${fileSrchPat}" "${fileReplPat}" 2>&1
fi
if [ ${dumB} -eq 1 ]
then
rm -fv "${fileBefore}" 2>&1
fi
rm -fv "findrep.txt" "custom.sed" "custom.err" "blockrep.sed" 2>&1
else
if [ ${dumA} -eq 1 ]
then
rm -f "${fileSrchPat}" "${fileReplPat}" 2>&1
fi
if [ ${dumB} -eq 1 ]
then
rm -f "${fileBefore}" 2>&1
fi
rm -f "findrep.txt" "custom.sed" "custom.err" "blockrep.sed" 2>&1
fi | awk '{ printf("\t %s\n", $0 ) ; }' >&2
else
echo -e "\t Failed to create '${fileOutput}'.\n" >&2
reportFiles | awk '{ printf("\t %s\n", $0 ) ; }' >&2
exit 1
fi
exit
Using the following command to execute (using default built-in demo case)
./script.sh --debug --review
The resulting session output is
======== fence 1
======== fence 2
======== fence 3
======== fence 4
======== fence 5
======== fence 6
======== fence 7
N
N
N
s/void Component::initialize()\
{\
my_component = new ComponentClass();\
}/void Component::initialize()\
{\
if (doInit)\
{\
my_component = new ComponentClass();\
}\
else\
{\
my_component.ptr = null;\
}\
}/
P
D
Hit return to continue ...
======== fence 8
======== fence 9
======== fence 10
other code1()
{
doing other things
doing more things
doing extra things
}
void Component::initialize()
{
if (doInit)
{
my_component = new ComponentClass();
}
else
{
my_component.ptr = null;
}
}
other code2()
{
creating other things
creating more things
creating extra things
}
-rw-rw-r-- 1 ericthered ericthered 71 Feb 4 16:05 File1.cpp
-rw-rw-r-- 1 ericthered ericthered 130 Feb 4 16:05 File2.cpp
-rw-rw-r-- 1 ericthered ericthered 220 Feb 4 16:05 findrep.txt
-rw-rw-r-- 1 ericthered ericthered 3604 Feb 4 16:05 blockrep.sed
-rw-rw-r-- 1 ericthered ericthered 0 Feb 4 16:05 custom.err
-rw-rw-r-- 1 ericthered ericthered 229 Feb 4 16:05 custom.sed
-rw-rw-r-- 1 ericthered ericthered 240 Feb 4 16:05 Test_INPUT.cpp
-rw-rw-r-- 1 ericthered ericthered 299 Feb 4 16:06 Test_OUTPUT.cpp
removed 'File1.cpp'
removed 'File2.cpp'
removed 'Test_INPUT.cpp'
removed 'findrep.txt'
removed 'custom.sed'
removed 'custom.err'
removed 'blockrep.sed'
Which is as was initially intended. Success!
sed
to solve this problem? It would be much easier to solve withawk
orperl
or many others. Good luck.sed: file blockrep.sed line 18: unterminated
s' command`. When I (thought) I fixed that, the script did not perform as expected. Did it work for you? Don't have much time to spend on this. Good luck in your endeavors!