0

我在一个文件中有多行。每行都有一个共同的开始标签和结束标签。我想获取标签之间的内容并将其放入由 /r 分隔的新文件中。

1)我尝试了以下..但它复制了整行并放入新文件

#!/bin/sh

startline="<Mytag>"
endline="<Nexttag>"

echo $startline
echo $endline

sed "/$startline/,/$endline/!d" input.txtt > test.txt

2)理想情况下,结束标签应该是</Mytag>,但 sed'/'不太好。如何克服这一点?我应该使用'//'吗?

谢谢


更新


input.txt 有以下几行

<?xml version="1.0" encoding="UTF-8" ?><InputRecord xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" <tag1>blah</tag1><mytag>myinfo</mytag><tag2>blah</tag2></InputRecord>

<?xml version="1.0" encoding="UTF-8" ?><InputRecord xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" <tag1>blah1</tag1><mytag>myinfo1</mytag><tag2>blah2</tag2></InputRecord>

预期产出

myinfo
myinfo1
4

3 回答 3

4

修改问题的答案

给定输入:

<?xml version="1.0" encoding="UTF-8" ?><InputRecord xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" <tag1>blah</tag1><mytag>myinfo</mytag><tag2>blah</tag2></InputRecord>
<?xml version="1.0" encoding="UTF-8" ?><InputRecord xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" <tag1>blah1</tag1><mytag>myinfo1</mytag><tag2>blah2</tag2></InputRecord>

输出应该是:

myinfo
myinfo1

暂时忽略使用正则表达式解析 XML 通常是不明智的,这可以被视为在单行上查找开始标记和结束标记之间的文本的请求。这转化为:

starttag="<mytag>"
endtag="</mytag>"
sed -n "\%.*$starttag\(.*\)$endtag.*% s//\1/p"

POSIX 要求该\%符号sed允许使用斜杠以外的其他内容作为正则表达式的分隔符。POSIXsed说:

... 一个上下文地址(由 BRE 组成,如正则表达式中所述sed,前后有一个分隔符,通常是 a <slash>

和:

在上下文地址中,除 or 以外的任何字符 的"\cBREc"结构应c与相同。如果 指定的字符出现在 a之后,那么它应该被认为是那个字面字符,它不会终止 BRE。例如,在上下文 address中,第二个代表它自己,因此 BRE 是。<backslash><newline>"/BRE/"c<backslash>"\xabc\xdefx"x"abcxdef"

回答问题的原始版本

$endline如果您获得正确的值,您的脚本应该可以正常工作。但是,IMNSHO,对打印范围持肯定态度更简单:

sed -n "/$startline/,/$endline/p" input.txtt > test.txt

意思是“-n除非我告诉你,否则不要打印”,脚本方式“在与起始行匹配的行和与结束行匹配的行之间打印。

对于带有斜杠的结束标记,您需要使用反斜杠转义斜杠:

endline="<\/Nexttag>"

或者您可以使用 a.代替斜线,理论上它可以匹配开头<XNexttag>但可能不会匹配。没有反斜杠可以解释为什么你得到了从开始行到文件结尾的所有内容。


关于积极性的好处

考虑数据文件:

line1
line2 start1
line3
line4 end1
line5
line6 start2
line7
line8 end2
line9

并考虑 shell 和sed命令:

echo Positive Single
sed -n -e '/start1/,/end1/p'  data
echo Negative Single
sed    -e '/start1/,/end1/!d' data

echo Positive Double
sed -n -e '/start1/,/end1/p'  -e '/start2/,/end2/p'  data
echo Negative Double
sed    -e '/start1/,/end1/!d' -e '/start2/,/end2/!d' data

运行该脚本的输出是:

$ sh sed.scripts
Positive Single
line2 start1
line3
line4 end1
Negative Single
line2 start1
line3
line4 end1
Positive Double
line2 start1
line3
line4 end1
line6 start2
line7
line8 end2
Negative Double
$

!d对于要匹配的单个模式范围的情况,公式与-n加公式没有问题p

但是,“正双”模式工作正常,产生了我期望的答案,“打印start1end1之间的线以及start2end2之间的线”,而“负双”模式不能正常工作更多的。我宁愿使用可扩展的版本,也不愿使用在需求发生变化时必须重写的版本。

于 2013-06-03T21:01:38.067 回答
3

要转义斜杠,请在它们前面加上反斜杠,如下所示:

<\/Nexttag>

但是您只需要它,因为您选择使用斜杠作为分隔符。您可以使用您想要的任何字符(通常选择斜线,因为许多其他语言使用它来分隔正则表达式)。所以选择一个不会出现在标签中的字符,比如哈希#:

sed "#$startline#,#$endline#!d" input.txtt > test.txt
于 2013-06-03T21:07:39.370 回答
1

这可能不是最佳解决方案,但它会为您的样本输入产生预期的输出:

#!/bin/sh

startline="<mytag>"
endline="<\/mytag>"

awk '{ gsub(">", "&\n"); gsub("<", "\n&"); print; }' | sed -e "/$startline/,/$endline/!d" -e "/$startline/d" -e "/$endline/d"

将您的示例输入重定向到此脚本,例如:

sh script.sh < sample.txt

中间awk只是在 毕竟>和之前放置一个换行符<,因为sed脚本只有在开始和结束标签单独在自己的行上时才有效。(说实话,这真的不是一个好剧本。)

于 2013-06-03T21:48:38.480 回答