I'm trying to do a multi-line sed range match. What I mean by this is that the beginning of the range is itself multiple lin开发者_运维百科es. The source looks like this
<filter-mapping>
<filter-name>Cache Filter - Resource</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Cache Filter - Resource</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Cache Filter - Resource</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Cache Filter - Resource JSP</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
And the only uniquely identifying segment to start the range is the entire first three lines, and the end of the range is identified by the entire last two lines.
Is there a way to specify a multiline pattern to begin a range match?
Alright, so I went with tchrist's solution and used perl instead. Here's what my regex looked like (in this example, I'm commenting out the xml). I'm also doing an inline replacement of the file.
perl -0777 -pi -e 's|([\t ]*<filter-mapping>\s*<filter-name>Cache Filter - Resource</filter-name>\s*<url-pattern>\*\.css[^\0]*<filter-name>Cache Filter - Resource JSP</filter-name>\s*<url-pattern>\*\.jsp</url-pattern>\s*</filter-mapping>)|<!-- \1 -->|g' inputfile
The best sed tutorial online covers this topic: http://www.grymoire.com/Unix/Sed.html#uh-51
If you're fairly new to sed, you probably want to start further up the page, like here: http://www.grymoire.com/Unix/Sed.html#uh-47
Using the Pearl approach (thanks! that was useful), I was only able to perform a multi-line match with the s modifier.
Since I'm using this for parameter replacement in Tomcat's web.xml, I place a copy of my bash script for anyone interested (comments are welcome).
#!/bin/bash
if [[ -z "$3" ]] ; then
echo "Sets a Tomcat web.xml parameter with a new value"
echo "SINTAX: $0 PARAM_NAME NEW_VALUE FILE"
exit 1
fi
PARAM_NAME="$1"
NEW_VALUE="$2"
FILE="$3"
perl -0777 -pi -e "s|(<param-name>${PARAM_NAME}</param-name>.*?<param-value>).*?(</param-value>)|\${1}${NEW_VALUE}\${2}|s" ${FILE}
Note: the part \${1} is done this way because ${NEW_VALUE} could be one or more digits and it would confuse perl.
Here is a processing using sed of multi-line:
sed ' /<filter-mapping>/,/<[/]filter-mapping>/{/filter-mapping/d}' FILE
This prints only the text between filter-maping
<filter-mapping>
TEXT
</filter-mapping>
I did not understand quite precisely what you want to do ...
You had best do this either with perl -0777 -pe 's/.../.../'
, or else use a proper parser.
Do not use sed
. Really.
精彩评论