Bob*_*man 6 xml sed awk text-processing regular-expression
所以我有一个任务,我必须通过 bash shell 脚本来操作 XML 文件。
以下是步骤:
以下是删除了非必要信息的 XML 示例:
<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
<fmreq:property>
<fmreq:name>form_category_cd</fmreq:name>
<fmreq:value>Memos</fmreq:value>
</fmreq:property>
<fmreq:property>
<fmreq:name>object_name</fmreq:name>
<fmreq:value>Correspondence</fmreq:value>
</fmreq:property>
</fmreq:fileManagementRequestDetail>
Run Code Online (Sandbox Code Playgroud)
我必须从 object_name 下的 value 元素中获取值,交叉引用它,然后用新值替换 form_category_cd value 元素下的值:
因此,如果 object_name -> value 是 Correspondence,那么 form_category_cd -> value 可能需要是 YYZ。
问题是,我只能使用我们服务器上可用的工具,因为我们的操作组限制我们使用手头的工具。这是一场争取更新 xmllint 然后被否决的斗争。我使用的版本不支持--xpath,相信我在美好的一天很难。此外,我可用的版本不支持命名空间,因此 xmllint 已出局。
我试过 sed,但它似乎不喜欢我的正则表达式,即使我尝试的每个测试器都工作正常。
正则表达式:
(<fmreq\:name>object_name<\/fmreq\:name>)(?:\n\s*)(<fmreq\:value>)(.*)(<\/fmreq\:value>)
Run Code Online (Sandbox Code Playgroud)
我需要获得第 3 组,但 sed 不会返回它。相反,它返回 XML 文件的全部内容。
sed -e 's/\(<fmreq\:name>object_name<\/fmreq\:name>\)\(?:\n\s*\)\(<fmreq\:value>\)\(.*\)\(<\/fmreq\:value>\)/\3/' < c3.xml
Run Code Online (Sandbox Code Playgroud)
我对 awk / gawk 不太熟悉,所以我也在努力弄清楚它们,但如果能找到解决方案,我会向他们开放。
很想有一个 awk / gawk 解决方案,只是为了让老板高兴,因为他是 awk 的老粉丝,但我会尽我所能,因为我很难过。
我再次必须使用手头的工具并且无法安装任何新的东西。
我认为您的命令存在几个问题sed
:
您不使用该-n
选项,因此默认情况下sed
仅将输入的每一行打印到输出(可能由sed
命令修改)。
您不需要重定向< c3.xml
,因为sed
将最后一个参数识别为文件名。
sed
不太适合多行匹配。参见此处的示例。
以下似乎适用于您的示例:
sed -n "/<fmreq:name>object_name<\/fmreq:name>/ {n;p}" c3.xml | sed "s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g"
Run Code Online (Sandbox Code Playgroud)
或者,仅sed
调用一次:
sed -n "/<fmreq:name>object_name<\/fmreq\:name>/ {n;s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g;p}" c3.xml
Run Code Online (Sandbox Code Playgroud)
该命令的作用细分:
该选项-n
指示sed
在处理完该行后不要打印模式空间。因此,您需要p
明确使用该命令来执行此操作。
/regex/
告诉sed
只执行匹配的行上的命令regex
。
该sed
命令n
将模式空间的内容替换为下一行输入,即包含您感兴趣的值的行。
该sed
命令将模式空间中的s/regex/replacement/
第一个匹配项替换为。regex
replacement
该sed
命令p
打印该行。