使用 bash 增加 xml 文件

使用 bash 增加 xml 文件

论坛上的一位好伙伴帮助我创建了这个脚本,但我向它抛出的所有内容都输出错误,我不知道为什么或问题是什么。如果被询问为 bash test.sh,我在 ubuntu 的终端中运行了所有脚本。

我的目标是增加多个 .xml 文件的process></process>标签,但某些文件可能有 1 到 100 个标签。

例子:

 - jfksaJDFH
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - jdhkjasdh
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>

脚本之后:

 - jfksaJDFH
 - <process>value="1"</process>
 - <process>value="2"</process>
 - <process>value="3"</process>
 - <process>value="4"</process>
 - jdhkjasdh
 - <process>value="5"</process>
 - <process>value="6"</process>
 - <process>value="7"</process>
 - <process>value="8"</process>

脚本:

#!/bin/bash

dir="/mnt/Desktop/test/"

while IFS= read -r -d '' file
do
    i=1
    while IFS= read -r -u 3 line
    do
        if [[ $line = '<process></process>' ]]; then
           echo "<process>value=\"$((i++))\"</process>"
        else
           echo "$line"
        fi
    done 3< "$file" > "$file.xml"
done < <(find $dir -type f -name \*.xml -print0)

当上面的脚本运行时删除最后一个<process>value=""</process>

将脚本修改为:

while IFS= read -r -d '' file
do
    i=1
    while IFS= read -r -u 3 line
    do
        if [[ $line = '<process></process>' ]]; then
           echo "$line"
        else
           echo "<process>value=\"$((i++))\"</process>"
        fi
    done 3< "$file" > "$file.xml"
done < <(find $dir -type f -name \*.xml -print0)

文件的输出是这样的:

<process>value="1"</process>
<process>value="2"</process>
<process>value="3"</process>
<process>value="4"</process>
<process>value="5"</process>
<process>value="6"</process>
<process>value="7"</process>
<process>value="8"</process>
<process>value="9"</process>
<process>value="10"</process>
<process>value="11"</process>
<process>value="12"</process>
<process>value="13"</process>
<process>value="14"</process>
<process>value="15"</process>
<process>value="16"</process>
<process>value="17"</process>
<process>value="18"</process>
<process>value="19"</process>
<process>value="20"</process>
<process>value="21"</process>
<process>value="22"</process>
<process>value="23"</process>

换句话说,这会增加但会删除页面中的所有其他内容。

答案1

将此脚本放入文件中(例如:'increase.awk'):

BEGIN { i = 1 }
/.*<process>value=""<\/process>.*/ { split($0, a, "value=\"\"") ; print a[1] "value=\"" i++ "\"" a[2] ; next }
/.*/ { print $0 }

然后调用:

gawk -f increase.awk < yourinputfile

解释:在 awk 中,split("string", a, "separatorstring")使用“separatorstring”作为分隔符,将“string”分割成一个名为 a 的数组。因此 a[1] 包含直到第一个“分隔符字符串”的所有内容,然后 a[2] 包含直到行尾或下一个“分隔符字符串”之前的所有内容,等等。

答案2

请不要这样做 XML。考虑一下您是否愿意 - XML 是一种主动忽略空格的结构化数据类型。具有一元标签,例如<attr name="fish" />和其他东西,这意味着如果您使用正则表达式逐行解析它,有一天您的代码将神秘地崩溃。

执行此操作的方法是使用 XML 解析器。使用哪一个是个人喜好的问题,但我喜欢脚本编写XML::Twig(perl 模块)。

要按照概述解决您的问题:

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

sub increment_value {
    my ( $twig, $process ) = @_;
    my ($value) = ( $process->text =~ m/(\d+)/ );
    print "Got $value\n";
    if ( defined ( $value ) ) { 
        $process->set_text( 'value="' . ++$value . '"' );
    } 
    else {
        $process -> delete;
    }
}

my $twig = XML::Twig->new(
    'pretty_print'  => 'indented',
    'twig_handlers' => { 'process' => \&increment_value },
);
$twig->parsefile( 'your_file.xml'  );
$twig->print;    #prints to stdout.

这会触发每个元素的“处理程序” process,用于提取、转换和替换文本。

答案3

您是否注意到,当您重写脚本时,您已经恢复了 if-then-else 构造的逻辑

请注意下面第 1 行和第 2 行注释行的位置。你在重写的代码中颠倒了它们

而 IFS= 读取 -r -d '' 文件
    我=1
    而 IFS= 读取 -r -u 3 行
        如果 [[ $line = '' ]];然后
           echo "value=\"$((i++))\"" # 第 1 行 ****************
        别的
           echo "$line" # 第 2 行 **************
    完成 3“$file.xml”
完毕

相关内容