【问题标题】:Use XMLStarlet to insert a single value too long to fit on a command line使用 XMLStarlet 插入一个太长而无法放入命令行的值
【发布时间】:2019-12-12 13:39:36
【问题描述】:

假设我有一个 xml 文件:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="a"></string>
</map>

我想用属性 a 来设置 string 的值,用一些大的东西:

$ xmlstarlet ed -u '/map/string[@name="a"]' -v $(for ((i=0;i<200000;i++)); do echo -n a; done) example.xml > o.xml

这将导致 bash 错误“参数列表太长”。我无法在 xmlstarlet 中找到接受文件结果的选项。那么,如何设置 200KB 数据+的 xml 标签的值呢?

解决方案

在尝试通过参数 -a (append) 将块输入 xmlstarlet 之后,我意识到我遇到了额外的困难,例如特殊字符的转义和 order哪个 xmlstarlet 接受这些块。 最终我恢复到更简单的工具,比如 xml2/sed/2xml。我将代码作为单独的帖子放在下面。

【问题讨论】:

  • 如果您想要破解,请将其设置为您确定在 xml 中不存在的某个字符串(例如 THIS_STRING_DOES_NOT_EXIST),然后使用 sed 或类似方法将 THIS_STRING_DOES_NOT_EXIST 替换为您想要的字符串工具。`
  • @anishsane 我只是想找到一种合法的方式来编辑 xml。
  • 您可以使用 xmlstarlet (append) 的 -a 选项而不是 -v,将命令减少到 20000 而不是 200000,然后循环 10 次。因此,您将在每个循环中附加 20000 个。
  • @Roadowl 有趣的提议。不过,我不会称其为合法方式。 :)
  • @Roadowl 有什么建议可以在 bash 中做到这一点吗?我尝试使用 xargs、read、echo 和 cut .... 的组合,但没有成功。让我们假设我们正在处理真实世界的数据,而不仅仅是一串“a”

标签: bash xmlstarlet


【解决方案1】:

这是您自己的示例的解决方法,该示例因 ARG_MAX 限制而爆炸:

#!/bin/bash
# (remove 'echo' commands and quotes around '>' characters when it looks good)

echo xmlstarlet ed -u '/map/string[@name="a"]' -v '' example.xml '>' o.xml

for ((i = 0; i < 100; i++))
do
    echo xmlstarlet ed -u '/map/string[@name="a"]' -a -v $(for ((i=0;i<2000;i++)); do echo -n a; done) example.xml '>>' o.xml
done

【讨论】:

    【解决方案2】:

    解决方案

    我并不为此感到自豪,但至少它有效。

    a.xml - what was proposed as an example in the starting post
    source.txt - what has to be inserted into a.xml as xml tag
    b.xml - output
    
    #!/usr/bin/env bash
    ixml="a.xml"
    oxml="b.xml"
    s="source.txt"
    echo "$ixml --> $oxml"
    
    t="$ixml.xml2"
    t2="$ixml.xml2.edited"
    t3="$ixml.2xml"
    
    # Convert xml into simple string representation
    cat "$ixml" | xml2 > "$t"
    
    # Get the string number of xml tag of interest, increment it by one and delete everything after it
    # For this to work, the tag of interest should be at the very end of xml file
    cat "$t" | grep -n -E 'string.*name=.*a' | cut -f1 -d: | xargs -I{} echo "{}+1" | bc | xargs -I{} sed '{},$d' "$t" > "$t2"
    # Rebuild the deleted end of the xml2-file with the escaped content of s-file and convert everything back to xml
    # * The apostrophe escape is necessary for apk xml files
    sed "s:':\\\':g" "$s" | sed -e 's:^:/map/string=:' >> "$t2"
    cat "$t2" | 2xml > "$t3"
    # Make xml more readable
    xmllint --pretty 1 --encode utf-8 "$t3" > "$oxml"
    
    # Delete temporary files
    rm -f "$t"
    rm -f "$t2"
    rm -f "$t3"
    

    【讨论】:

      猜你喜欢
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-19
      • 1970-01-01
      • 1970-01-01
      • 2019-11-28
      • 2020-06-07
      相关资源
      最近更新 更多