通过shell脚本设置XML标记

时间:2012-11-22 15:17:41

标签: xml shell unix xml-parsing sed

我很困惑,使用shell脚本设置XML的标记值(Value可能包含特殊字符)。

XML标记值应该是双引号。

要求: 我有一个带有标签值的xml。对于shell脚本,我必须添加一个带有值的新XML标签 在标签之前。 所以我正在使用sed,我尝试如下。如果$ 4 $ 5没有特殊字符,这可以正常工作。如何使用特殊字符进行此工作?(例如:&><:"。,;& #39;等)

sed '/<jobResulsDir/s/<jobResulsDir/<CommCellUser userName="'$4'" password="'$5'" >  <\/CommCellUser> '$test' <jobResulsDir  /' $temp_dir/PreImageModeFile.xml > $temp_dir/PreImageModeFile2.xml

除了sed还有其他方法。请帮助我

3 个答案:

答案 0 :(得分:0)

为什么不使用perl?它必须是一个shell脚本。

   #!/usr/bin/perl
   use XML::Simple;
   use Data::Dumper;
   open(my $XML_IN, '<', '/xml/file/path.xml');
   $/=undef;
   my $xml_ref = XMLIn(<$XML_IN>);
   print Dumper \$xml_ref;
   # ... access $xml_ref in appropriate location, adding element / value
   my $new_xml = XMLout($xml_ref);
   close $XML_IN;
   open(my $XML_OUT, '>', '/xml/file/path.xml');
   print $XML_OUT $new_xml;
   close $XML_OUT;

答案 1 :(得分:0)

你试图用sed做什么会撕掉你的大脑,你必须在每个特殊角色之前使用反斜杠才能让它运转起来。我用m4做这种工作。观看一个例子:

define(your_macro_name,<Delete>
<Object fdn="SubNetwork=somemoredata`,SubNetwork=somedata'`,ManagedElement'=$1"/>
</Delete>)dnl

将上述代码保存在名为“xmlmacros.m4”的文件中 然后创建一个名为“test.m4”的文件并添加以下内容:

include(xmlmacros.m4)dnl
your_macro_name(YOURXMLVALUE)

如果这两个文件位于同一个文件夹中,则可以运行m4 test.m4,输出将为:

 <Delete>
 <Object fdn="SubNetwork=somemoredata,SubNetwork=somedata,ManagedElement=YOURXMLVALUE"/>

其中$1将替换为“test.m4”文件括号中的值。您还可以添加更多定义,按需创建xml文件,例如xml标题等。

以上是您可以使用的工作示例。您可以浏览一下有关m4的更多信息,我总是将它用于此类工作。

答案 2 :(得分:0)

Awk并不关心“特殊字符”。这在sed:

sed '/<jobResulsDir/s/<jobResulsDir/<CommCellUser userName="'$4'" password="'$5'" > <\/CommCellUser> '$test' <jobResulsDir /'

这是awk:

awk -v userName="$4" -v password="$5" -v test="$test" '
   /<jobResulsDir/{ sub(/<jobResulsDir/, "<CommCellUser userName=" userName " password=" password " </CommCellUser> " test " <jobResulsDir ") }
   { print }
'

但您实际上并不需要预先测试/<jobResulsDir/,因为只有RE存在才会出现sub(),因此您可以将其缩写为:

awk -v userName="$4" -v password="$5" -v test="$test" '
   { sub(/<jobResulsDir/, "<CommCellUser userName=" userName " password=" password " </CommCellUser> " test " <jobResulsDir "); print }
'

不确定这是否是您的评论/问题,但如果您需要围绕值名称使用双引号,只需调整脚本以便在需要的地方提供:

awk -v userName="$4" -v password="$5" -v test="$test" '
   { sub(/<jobResulsDir/, "<CommCellUser userName=\"" userName "\" password=\"" password "\" </CommCellUser> \"" test "\" <jobResulsDir "); print }
'

最后,如果您愿意,可以通过以下方式将工作分解为更具可读性和效率:

awk -v userName="$4" -v password="$5" -v test="$test" '
   BEGIN{
      q = "\""
      rep = \
         "<CommCellUser userName=" q userName q\
         " password="              q password q\
         " </CommCellUser> "       q test     q\
         " <jobResulsDir "
   }
   { sub(/<jobResulsDir/, rep); print }
'

看着它的方式,我意识到我撒谎了一点关于awk不关心“特殊人物”。 sub()实际上关心1“特殊字符”,那是“&amp;”在替换字符串中,因为它用于反向引用sub()中匹配的内容,因此您需要在rep中用“\&amp;”替换“&amp;”s:

awk -v userName="$4" -v password="$5" -v test="$test" '
   BEGIN{
      q = "\""
      rep = \
         "<CommCellUser userName=" q userName q\
         " password="              q password q\
         " </CommCellUser> "       q test     q\
         " <jobResulsDir "
   }
   { gsub(/&/,"\\\\&",rep); sub(/<jobResulsDir/, rep); print }

它需要4“\”,因为字符串文字在awk中被解释两次(一次解释脚本时再次执行),而不是\得到文字反斜杠,你需要\\。

如果您愿意,还有一种使用match()和substr()的替代方法没有该约束:

awk -v userName="$4" -v password="$5" -v test="$test" '
   BEGIN{
      q = "\""
      rep = \
         "<CommCellUser userName=" q userName q\
         " password="              q password q\
         " </CommCellUser> "       q test     q\
         " <jobResulsDir "
   }
   match($0,/<jobResulsDir/) {
       $0 = substr($0,1,RSTART) rep substr($0,RSTART+RLENGTH)
   }
   { print }
'

就个人而言,我会选择match()/ substr()方法,因为我讨厌使用转义字符。

只是为了循环回到我们开始的地方,如果你愿意的话,你可以把它写成一个单行:

awk -v userName="$4" -v password="$5" -v test="$test" '{
   print (match($0,/<jobResulsDir/) ? substr($0,1,RSTART) "<CommCellUser userName=\"" userName "\"password=\"" password "\" </CommCellUser> \"" test "\" <jobResulsDir " substr($0,RSTART+RLENGTH) : $0)
}'