【问题标题】:Inserting new line in txt file using CygWin使用 CygWin 在 txt 文件中插入新行
【发布时间】:2019-01-24 12:11:06
【问题描述】:

我有一个 XML 表,其行结构如下:

<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
</row>

我想做的是在第 12 列之后添加第 13 列,它需要有一个递增的数字作为其值作为主键(从 1 开始,每行增加 1,如 X++ 等) .值得注意的是大约有 2000 万行。

我一直在尝试使用 CygWin (Mintty) 来解决这个问题,但我完全没有使用它或任何 Unix 的经验,这只是我被推荐的第一件事,它实际上能够加载这些可怕的 XML文件。

对于初学者,我尝试使用 Sed 使用以下命令插入第 13 列:

-i -e 's/\/C12>/\/C12><C13><\/C13>/g' t1s.txt

我的想法是我会用它本身 + 第 13 列替换关闭的 C12 括号。相反,它只是用 C13 替换了 C12,就好像斜线没有正确转义一样。

可能有一个“插入”而不是“替换”的命令,这使得我正在尝试做的事情看起来完全疯狂,但我不知道那个命令会是什么并且没有太多的运气搜索。我最接近的方法是改用 AWK,如果这对 Sed 不可行,我愿意这样做,但我不知道怎么做,而且似乎也有点困难。

我希望实现的是将文档更改如下(这很长,但是如果不包括所有内容显然没有意义。这个问题只涉及如何在每行中添加第13列,其他 12 个只是上下文):

<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>1</C13>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>2</C13>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>3</C13>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>4</C13>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>5</C13>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>foobar</C3>
    <C4>foobar</C4>
    <C5>foobar</C5>
    <C6>foobar</C6>
    <C7>foobar</C7>
    <C8>foobar</C8>
    <C9>foobar</C9>
    <C10>foobar</C10>
    <C11>foobar</C11>
    <C12>foobar</C12>
    <C13>6</C13>
</row>

这持续了几百万行......

请注意,唯一的变化是增加了第 13 列,并且每行的值都在增加。这就是这个问题的全部内容,其他 12 列只是周围的结构。

【问题讨论】:

  • 其实是为了说明有12个columns都与这个问题完全无关。我只想添加第 13 列,这个问题只涉及该列。我将尝试编辑问题以反映这一点。
  • @Ed Morton 在那里,我编辑了示例以显示所有列。它现在相当庞大,但我希望它更有意义。请再次注意,每行中的前 12 列不是问题的一部分,它们包含的数据对问题并不重要,这就是我在其值中写“foobar”的原因。
  • 现在有意义吗?我不确定这其中的哪一部分一开始就不清楚。我只是想在 XML 表中插入一个列并分配它的值。至少在概念上,我认为这是非常基本的。
  • 这篇文章在第一行字面上说“行结构如下”,这意味着这是 2000 万行中的一个示例,我需要通过添加另一个来更改每一行列。我包括了 12 个 foobar 行,以防有人编写脚本等,将行号、缩进等考虑在内。另外,在我看来,您在这里自相矛盾。你说我应该删掉一些列,但指责我没有完全按照预期定义输入/输出。我真的没有其他东西可以添加到输入或输出中。
  • 至于第二个...输出。它下面的第一行字面意思是“这持续了几百万行”。所以 6 只是一个随机数,因为我显然不能发布其中的 2000 万个,但有人告诉我,第 13 行的“计数器”的概念很难想象(我也不明白,因为我明确表示它是一个主键,这几乎就是它们的外观),所以我显示它数到 6。可能是 4。可能是 11.673.201。没关系,我展示了我希望第 13 行出现在哪里以及我希望如何分配它的值。

标签: xml unix awk sed cygwin


【解决方案1】:

要编辑 XML 文件,最好使用 XML 解析器。

这是使用xmlstarlet(在Cygwin 中可用)将包含文本foobar 的节点C13 插入到您的XML 文件中的命令:

xmlstarlet ed --subnode "/row" -t elem -n C13 -v foobar ts1.txt
  • ed:编辑/更新 XML 文档
  • --subnode "/row":在row节点内添加一个节点
  • -t elem: 类型是元素
  • -n C13:名字是C13
  • v foobar:值为foobar

【讨论】:

  • xmlstartlet 也可以在行中添加增量值吗?如果有,怎么做?
  • @Noobie 增量值是什么意思?请用这样的例子更新你的问题。
  • 基本上类似于 X++,如果 X 从 1 开始,并且对于它出现的每一行都增加 1,基本上是对用作主键的行进行编号。
  • @Noobie 这很可能通过结合使用xmlstarlet 和bash 语句来实现。但我不知道您的意思是增加节点名称、其值还是其他&lt;row&gt; 节点...请用有意义的示例更新您的问题。
  • 值。我试着总结出想要的结果。这有意义吗?
【解决方案2】:

使用xmlstarlet 和 XSLT 转换:

给定这个 XSLT 文件

$ cat f.xslt 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!-- Identity transform -->
    <xsl:template match="/ | @* | node()">
            <xsl:copy>
                    <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
    </xsl:template>
    <xsl:template match="/">
            <xsl:for-each select="/doc/row">
                    <xsl:copy>
                            <xsl:apply-templates select="@* | node()"/>
                            <C13><xsl:value-of select="position()"/></C13>
                    </xsl:copy>
            </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

假设&lt;row&gt;...&lt;/row&gt; 包含在标签&lt;doc&gt;...&lt;/doc&gt; 中,您可以使用以下命令添加C13 节点及其计数:

xmlstarlet tr f.xslt file

tr 表示“转置”并使用 XSLT 文件修改给定的file

XSLT 主要包含 2 个块。
一个称为“身份”的人实际上将输入保留为原样。第二个块查找每个&lt;doc&gt;&lt;row&gt; 并复制其内容并添加带有计数的&lt;C13&gt; 节点。

致谢:herehere

【讨论】:

  • 感谢您的回复。这些行没有包含在 doc 标签中,但是它们包含在 table 标签中。澄清一下,整个文档结构是顶部的声明行,然后是包含所有行的表格标记。仅此而已。是否可以以适应此的方式应用此解决方案?
  • @Noobie 只需将&lt;xsl:for-each select="/doc/row"&gt; 行中的doc 替换为XML 文件中包含&lt;row&gt; 的标签名称。
  • 好吧,如果它们都包含在同一个标​​签/父级中,这是否可行,或者它们是否需要各自有不同的父级?可能是一个愚蠢的问题,但我只是想确定一下。 :) 非常感谢您的努力。
  • @Noobie 据我所知,一个有效的 XML 文件有一个根标签(例如 HTML 文档和 &lt;html&gt;...&lt;/html&gt; 标签)。所以它必须在一个根标签中。只要select 路径正确,&lt;row&gt; 的位置有多深并不重要。
  • 好吧,那么看来table标签就是根标签了。谢谢,将以此作为我的指导方针。再次感谢!
【解决方案3】:

如果您的输入真的那么常规和简单,那么您所需要的就是:

awk '{print} sub(/<C12>.*/,""){print $0"<C13>"++cnt"</C13>"}' file

但没有具体的东西来测试它的猜测。这就是我认为你正在尝试使用 MCVE 做的事情,每个块有 2 个 foobars 而不是 12 个:

$ cat file
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
</row>

$ awk '{print} sub(/<C2>.*/,""){print $0"<C3>"++cnt"</C3>"}' file
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>1</C3>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>2</C3>
</row>
<row>
    <C1>foobar</C1>
    <C2>foobar</C2>
    <C3>3</C3>
</row>

请注意,数字 12 和 13 可以通过调整从您的输入中生成,它们不需要在脚本中硬编码 top,但如果有必要,请注意,所以我没有费心去做。

【讨论】:

  • 这正是我想要做的,实际上就是这么简单。您的解决方案比当前的解决方案简单得多,所以我将试一试。另外,我完全知道在这个解决方案中列的数量并不重要,但是当我问这个问题时我不确定是否会出现这种情况,这就是为什么所有 12 个都在那里。
  • 这就是您在问题文本“我的真实输入有 12 列...”中所说的内容,以及您为我们提供的 minimal reproducible example 来测试“这是一个有 2 列的 MCVE...” .它们不必完全相同才能获得好的解决方案 - 只需通过在多于 1 个案例中提供 2 或 3 个实例来区分示例中的 1 个实例和多于 1 个实例,并在文本中说明您的真实情况“大于 1" 的值是。
  • 好的。从现在开始就这样接近它。虽然在互联网上呆了几年,但如果有一天我遇到有人以完全相反的立场批评我,我不会感到惊讶。唉,你提出了我所希望的最好的解决方案,所以我会相应地考虑你对问题结构的看法。
  • 顺便问一下,有没有办法可以改变这个解决方案,让它把这个变化写入文件而不是在控制台中打印?
  • 好的,然后将使用输出文件。这样可以更轻松地测试实际文件。再次感谢您的努力和耐心。我会以多种方式认为这是一种学习体验。
猜你喜欢
  • 2013-02-24
  • 2019-04-21
  • 2015-01-15
  • 1970-01-01
  • 2015-09-01
  • 2014-02-02
  • 2014-04-05
  • 2022-01-01
  • 1970-01-01
相关资源
最近更新 更多