0

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

XML 标记值应该用双引号括起来。

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

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

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

4

3 回答 3

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"/>

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

以上是您可以使用的工作示例。您可以四处寻找有关 m4 的更多信息,我总是将它用于此类工作。

于 2012-11-22T15:39:42.240 回答
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/因为 sub() 仅在 RE 存在时才会发生,因此您可以将其缩写为:

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 个“特殊字符”,即替换字符串中的“&”,因为它用于反向引用 sub() 中匹配的内容,因此您需要将“&”替换为“\&”在代表:

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)
}'
于 2012-11-22T15:45:50.360 回答
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;
于 2012-11-22T15:34:49.817 回答