[英]Trying to get generic sed multi-line pattern match and substitution script to work
在linuxtopia here的第 4.23.3 节中,有一种通用方法可以解决此海报所呈现的问题。 它似乎提供了一种方法来处理匹配目标的任何复杂内容模式,然后再次将其替换为任何其他复杂内容模式。 该技术被称为“滑动窗口”技术。
我相信下面的脚本忠实地再现了所描述的场景,并尝试结合 sed 脚本来证明该方法是可行的。
#!/bin/bash
DBG=1
###
### Code segment to be replaced
###
file1="File1.cpp"
rm -f "${file1}"
cat >"${file1}" <<"EnDoFiNpUt"
void Component::initialize()
{
my_component = new ComponentClass();
}
EnDoFiNpUt
test ${DBG} -eq 1 && echo "fence 1"
###
### Code segment to be used as replacement
###
file2="File2.cpp"
rm -f "${file2}"
cat >"${file2}" <<"EnDoFiNpUt"
void Component::initialize()
{
if (doInit)
{
my_component = new ComponentClass();
}
else
{
my_component.ptr = null;
}
}
EnDoFiNpUt
test ${DBG} -eq 1 && echo "fence 2"
###
### Create demo input file
###
testfile="Test_INPUT.cpp"
rm -f "${testfile}"
{
echo "
other code1()
{
doing other things
doing more things
doing extra things
}
"
cat "${file1}"
echo "
other code2()
{
creating other things
creating more things
creating extra things
}
"
} >>"${testfile}"
test ${DBG} -eq 1 && echo "fence 3"
###
### Create editing specification file
###
{
cat "${file1}"
echo "###REPLACE_BY###"
cat "${file2}"
} >findrep.txt
test ${DBG} -eq 1 && echo "fence 4"
###
### sed script to create editing instructions to apply aove editing specification file
###
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
# 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.
:a
/^###REPLACE_BY###$/! {
# Escape slashes, backslashes, the final newline and
# regular expression metacharacters.
s,[/\[.*],\\&,g
s/$/\\/
H
#
# Append N cmds needed to maintain the sliding window.
x
1 s,^.,s/,
1! s/^/N\
/
x
n
ba
}
#
# Change the final backslash to a slash to separate the
# two sides of the s command.
x
s,\\$,/,
x
#
# Until EOF, gather the substitution into hold space.
:b
n
s,[/\],\\&,g
$! s/$/\\/
H
$! bb
#
# Start the RHS of the s command without a leading
# newline, add the P/D pair for the sliding window, and
# print the script.
g
s,/\n,/,
s,$,/\
P\
D,p
#---end of script---
EnDoFiNpUt
test ${DBG} -eq 1 && echo "fence 5"
sed --debug -nf blockrep.sed findrep.txt >custom.sed
test ${DBG} -eq 1 && echo "fence 6"
if [ -s custom.sed ]
then
more custom.sed
echo -e "\t Hit return to continue ..." >&2
read k <&2
else
echo -e "\t Failed to create 'custom.sed'. Unable to proceed!\n" >&2
exit 1
fi
testout="Test_OUTPUT.cpp"
sed -f custom.sed "${testfile}" >"${testout}"
test ${DBG} -eq 1 && echo "fence 7"
if [ -s "${testout}" ]
then
more "${testout}"
else
echo -e "\t Failed to create '${testout}'.\n" >&2
exit 1
fi
不幸的是,他们提出的似乎不起作用。 我希望有类似 bash 的“set -x”的命令扩展/报告 sed 执行到 stderr,但我还没有找到类似的东西。
上面的执行日志如下:
fence 1
fence 2
fence 3
fence 4
fence 5
sed: file blockrep.sed line 19: unterminated `s' command
fence 6
Failed to create 'custom.sed'. Unable to proceed!
也许那里的专家可以解决导入的blockrep.sed脚本中的逻辑错误...因为即使提供了所有评论,我也无法全神贯注地修复它。
我公开证明我对 sed 的知识和使用都非常简单/有限。我无法开始理解那个“ blockrep.sed ”脚本是如何尝试做它声称的,只是它说明findrep.txt的所有内容,在定义的分隔符字符串“ ###REPLACE_BY### ”之前,将被同一分隔符下方的所有内容替换。
在我看来,linuxtopia 指南确定的方法将具有广泛的应用,并且对包括 OP 和我自己在内的许多人都有好处。
我对blockrep.sed脚本的部分进行了离散化,以查看是否可以确定故障源。 虽然这在表面上没有逻辑上的区别,但它确实创建了一个功能良好且格式正确的结构......它确实创建了一个可用的custom.sed ,但只有在我删除了执行blockrep.sed的--debug选项之后。 这是必需的,因为 degug 信息不会发送到 stderr,而是与 stdout 内联!!! 我不知道将其归类为错误。
脚本的工作版本如下:
#!/bin/bash
DBG=1
file1=""
file2=""
#divider=""
doReview=0
while [ $# -gt 0 ]
do
case $1 in
--old_pattern ) file1="$2" ; shift ; shift ;;
--new_pattern ) file2="$2" ; shift ; shift ;;
#--pattern_sep ) divider="$2" ; shift ; shift ;; ### Not yet implemented
--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 "${file1}" ]
then
file1="File1.cpp"
rm -f "${file1}"
cat >"${file1}" <<"EnDoFiNpUt"
void Component::initialize()
{
my_component = new ComponentClass();
}
EnDoFiNpUt
test ${DBG} -eq 1 && echo "fence 1"
fi
###
### Code segment to be used as replacement
###
if [ -z "${file2}" ]
then
file2="File2.cpp"
rm -f "${file2}"
cat >"${file2}" <<"EnDoFiNpUt"
void Component::initialize()
{
if (doInit)
{
my_component = new ComponentClass();
}
else
{
my_component.ptr = null;
}
}
EnDoFiNpUt
test ${DBG} -eq 1 && echo "fence 2"
fi
###
### Create demo input file
###
testfile="Test_INPUT.cpp"
rm -f "${testfile}"
{
echo "
other code1()
{
doing other things
doing more things
doing extra things
}
"
cat "${file1}"
echo "
other code2()
{
creating other things
creating more things
creating extra things
}
"
} >>"${testfile}"
test ${DBG} -eq 1 && echo "fence 3"
###
### Create editing specification file
###
{
cat "${file1}"
echo "###REPLACE_BY###"
cat "${file2}"
} >findrep.txt
test ${DBG} -eq 1 && echo "fence 4"
###
### sed script to create editing instructions to apply above editing specification file
if [ ! -s "blockrep.sed" ]
then
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
# 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.
##############################################################################
### Original coding from linuxtopia
##############################################################################
### :markerA
### /^###REPLACE_BY###$/! {
### # Escape slashes, backslashes, the final newline and
### # regular expression metacharacters.
### s,[/\[.*],\\&,g
### ### add backslash to end of line (to avoid having sed think of as end of command input
### s,$,\\,
### H
### #
### # Append N cmds needed to maintain the sliding window.
### x
### 1 s,^.,s/,
### 1! s,^,N\
### ,
### x
### n
### b markerA
### }
##############################################################################
### Discretized version of coding
##############################################################################
:markerA
/^###REPLACE_BY###$/! {
#
# 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,$,\\,
H
#
# Append N cmds needed to maintain the sliding window.
x
1 s,^.,s/,
1! s,^,N\
,
x
n
b markerA
}
##############################################################################
#
# Change the final backslash to a slash to separate the
# two sides of the s command.
x
s,\\$,/,
x
#
# Until EOF, gather the substitution into hold space.
:markerB
n
s,[/],\\&,g
s,[\],\\&,g
$! s,$,\\,
H
$! b markerB
#
# Start the RHS of the s command without a leading
# newline, add the P/D pair for the sliding window, and
# print the script.
g
s,/\n,/,
s,$,/\
P\
D,p
#---end of script---
EnDoFiNpUt
fi
test ${DBG} -eq 1 && echo "fence 5"
rm -fv custom.sed custom.err
#sed --debug -f blockrep.sed findrep.txt >custom.sed 2>custom.err
sed -nf blockrep.sed findrep.txt >custom.sed 2>custom.err
if [ -s custom.err ]
then
if [ ${doReview} -eq 1 ]
then
cat custom.err
fi
fi
test ${DBG} -eq 1 && echo "fence 6"
if [ -s custom.sed ]
then
if [ ${doReview} -eq 1 ]
then
more custom.sed
echo -e "\t Hit return to continue ..." >&2
read k <&2
fi
else
echo -e "\t Failed to create 'custom.sed'. Unable to proceed!\n" >&2
exit 1
fi
testout="Test_OUTPUT.cpp"
sed -f custom.sed "${testfile}" >"${testout}"
test ${DBG} -eq 1 && echo "fence 7"
if [ -s "${testout}" ]
then
if [ ${doReview} -eq 1 ]
then
more "${testout}"
fi
else
echo -e "\t Failed to create '${testout}'.\n" >&2
exit 1
fi
exit
结果 session output 是
fence 1
fence 2
fence 3
fence 4
fence 5
removed 'custom.sed'
removed 'custom.err'
fence 6
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 7
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
}
这是最初的意图。 成功!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.