使用 bash 或 perl 提取两个不同字符串之间的内容

Extracting the contents between two different strings using bash or perl

为此,我已尝试浏览堆栈溢出中的其他帖子,但无法使我的代码正常工作,因此我发布了一个新问题。

以下是文件temp的内容。

 <?xml version="1.0" encoding="UTF-8"?>
 <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/<env:Body><dp:response xmlns:dp="http://www.datapower.com/schemas/management"><dp:timestamp>2015-01-
 22T13:38:04Z</dp:timestamp><dp:file name="temporary://test.txt">XJzLXJlc3VsdHMtYWN0aW9uX18i</dp:file><dp:file name="temporary://test1.txt">lc3VsdHMtYWN0aW9uX18i</dp:file></dp:response></env:Body></env:Envelope>

此文件包含两个文件名test.txttest1.txt的base64编码内容。我想提取每个文件的 base64 编码内容以分别分隔文件 test.txttext1.txt

为此,我必须删除 base64 内容周围的 xml 标记。我正在尝试使用以下命令来实现这一目标。但是,它没有按预期工作。

sed -n '/test.txt"\>/,/\<\/dp:file\>/p' temp | perl -p -e 's@<dp:file name="temporary://test.txt">@@g'|perl -p -e 's@</dp:file>@@g' > test.txt

sed -n '/test1.txt"\>/,/\<\/dp:file\>/p' temp | perl -p -e 's@<dp:file name="temporary://test1.txt">@@g'|perl -p -e 's@</dp:file></dp:response></env:Body></env:Envelope>@@g' > test1.txt

以下命令:

sed -n '/test.txt"\>/,/\<\/dp:file\>/p' temp | perl -p -e 's@<dp:file name="temporary://test.txt">@@g'|perl -p -e 's@</dp:file>@@g'

产生输出:

 XJzLXJlc3VsdHMtYWN0aW9uX18i

<dp:file name="temporary://test1.txt">lc3VsdHMtYWN0aW9uX18i</dp:response>   </env:Body></env:Envelope>` 

然而,在输出中我只期待第一行 XJzLXJlc3VsdHMtYWN0aW9uX18i。我哪里错了?

当我在命令下 运行 时,我得到了预期的输出:

sed -n '/test1.txt"\>/,/\<\/dp:file\>/p' temp | perl -p -e 's@<dp:file name="temporary://test1.txt">@@g'|perl -p -e 's@</dp:file></dp:response></env:Body></env:Envelope>@@g'

它产生以下字符串

lc3VsdHMtYWN0aW9uX18i

然后我可以轻松地将其路由到 test1.txt 文件。

更新

我已经通过更新源文件内容编辑了问题。源文件不包含任何换行符。当前的解决方案在那种情况下不起作用,我已经尝试过但失败了。 wc -l temp 必须输出到 1

OS: solaris 10 Shell: bash

sed -n 's_<dp:file name="\([^"]*\)">\([^<]*\).*_ -> _p' temp
  • 我添加 -> 以显示 link 从文件名到内容,但仅对于内容,只需删除这部分
  • posix 版本所以 GNU sed 使用 --posix
  • 假设base64编码的内容与周围的标签在同一行(而不是分散在几行,在这种情况下需要一些修改)

感谢 JID 的完整解释


工作原理

sed -n

-n 表示不打印,因此除非明确告知要打印,否则 sed

不会有任何输出
's_

这是用 _ 将正则表达式与替换项分开来替换以下正则表达式。

<dp:file name=

常规文本

"\([^"]*\)"

方括号是捕获组,必须转义,除非使用 -r 选项(-r 在 posix 上不可用)。括号内的所有内容都被捕获。 [^"]* 表示任何不是引号的字符出现 0 次或多次。所以实际上这只是捕获了两个引号之间的任何内容。

>\([^<]*\)<

这次再次使用捕获组来捕获><

之间的所有内容
.*

其他都行

_ -> 

这是替换,所以用第一个捕获组替换之前正则表达式中的所有内容,然后是 ->,然后是第二个捕获组。

_p

表示打印行


资源

http://unixhelp.ed.ac.uk/CGI/man-cgi?sed

http://www.grymoire.com/Unix/Sed.html

/usr/xpg4/bin/sed 在这里效果很好。

如果文件仅包含 1 行,

/usr/bin/sed 无法按预期工作。

以下命令适用于仅包含一行的文件。

/usr/xpg4/bin/sed -n 's_<env:Envelope\(.*\)<dp:file name="temporary://BackUpDir/backupmanifest.xml">\([^>]*\)</dp:file>\(.*\)__p' securebackup.xml 2>/dev/null

如果没有 2>/dev/null,此 sed 命令会输出警告 sed: Missing newline at end of file

这是因为以下原因:

Solaris 默认的 sed 忽略最后一行不破坏现有脚本,因为在原始 Unix 实现中要求一行以新行终止。

GNU sed 有更宽松的行为,POSIX 实现接受事实但输出警告。