使用 bash 脚本在 XML 文件中查找选项块

Use a bash script to find a block of options within an XML file

我有一个 XML 文件,其结构如下:

<?xml version="1.0" encoding="utf-8"?>
<questions>
    <property name="q154">
        <q154>
            <Property name="intro" value="Based on the information, {{1}} is older than {{2}}"/>
            <Property name="op1">
                <Pstructure>
                    <Property name="choices">
                        <Value>Mary</Value>
                        <Value>John</Value>
                        <Value>Carl</Value>
                    </Property>
                    <Property name="correct-indices">
                        <Value>3</Value>
                    </Property>
                    <Property name="hints">
                        <Value>Some hint here</Value>
                        <Value>blah blach blah</Value>
                    </Property>
                </Pstructure>
            </Property>
            <Property name="op2">
                <Pstructure>
                    <Property name="choices">
                        <Value>Albert</Value>
                        <Value>Nicole</Value>
                        <Value>Lizeth</Value>
                    </Property>
                    <Property name="correct-indices">
                        <Value>1</Value>
                    </Property>
                    <Property name="hints">
                        <Value>Some hint here</Value>
                        <Value>blah blah blah</Value>
                    </Property>
                </Pstructure>
            </Property>
        </q154>
    </property>
    <property name="q155">
        <q155>
            </Property name="intro" value="You get the idea ......."/>
            </Property>
        </q155>
    </property>
</questions>

如您所见,有介绍性文本、一些要随时替换的变量({{1}} 和 {{2}})、选项、提示等...

我想做的是创建一个 bash 脚本来查看整个文件,如果找到“变量”{{1}} 或 {{2}},它将打印整个介绍文本以及行号,在此下方,每个特定变量可用的相应选项。

所以,脚本的输出将是这样的:

user@debian: ~/projectx$ ./myscript.sh questions01.xml

::: Finding variables and options in questions01.xml...
96: Based on the information, {{1}} is older than {{2}}
97: ...op1
99: ....choices
100: ..... Mary
101: ..... John
102: ..... Carl
113: ...op2
115: ....choices
116: ..... Albert
117: ..... Nicole
118: ..... Lizeth
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
190: The winner of the race was {{1}}
191: ...op1
193: ....choices
194: ..... Lewis Hammilton
195: ..... Valtteri Bottas
196: ..... Daniel Ricciardo
197: ..... Kimi Raikkonen

这是我目前拥有的:

for f in ""*.xml
    do
        echo ::: Finding variables and options in $f...
        vars=$(grep -nEo ".{0,30}{{[0-9]}}.{0,30}" $f | uniq)
        if [ -n "$vars" ]
        then
            echo "$vars"
        fi
done

内容不多,但我得到了变量列表,以及一些上下文(每边 30 个字符)和行号。

如何将此变量列表传递给某个函数或方法以获取其余缺少的信息,以便获得我在上面发布的输出?

PS: 不一定非要用grep,其他方式都可以,只要打印出相同的输出即可。

编辑 1: 如果我把需求分成几个步骤,它会是这样的:

  1. 找到每个变量 {{1}} 或 {{2}} 并获取它所在的行号
  2. 打印找到变量的整个“介绍”文本
  3. 在该行号之后,找到下一个出现的“op1”或“op2”...取决于{{1}} {{2}}...
  4. 找到“opX”出现后,找到下一个“选择” 属性
  5. 现在,在那个“选择”块中,找到每个 标签,然后 打印其内容。
  6. 重复循环...

那么,输出结果就是上面所说的

使用以下行创建 shell 脚本 (myscript.sh):

#!/bin/bash
cat -n $* | perl -ne '
print "::::::::::::::::::\n$_" if /<Property name="intro"/;
print if /"op\d"/../"correct-indices"/;
' | perl -ne '
next if /<Pstructure>/ || m{</Property>} || /"correct-indices">/;
s/"intro"\s+value="//;
s/"(op\d+)">//;
s/<Property name=//;
s/"choices">/choices/;
s{<value>}{}i;
s{</value>}{}i;
s{"/>}{};
print;
' | perl -ne '
s/\s+(.+?\{\{\d\}\}.+)//;
s/\s+(op\d)/.../;
s/\s+choices/....choices/;
s/^\s+(.+?)/...../;
print;
' | perl -pe '
s/^(\.+?)(\d+)\t\s+/: /;
s/\t\s+/: /;
s/^\.+(\d+)(\.+?)/: /;'

执行它./myscript.sh questions01.xml将导致

::::::::::::::::::
5: Based on the information, {{1}} is older than {{2}}
6: ...op1
8: ....choices
9: .....Mary
10: .....John
11: .....Carl
22: ...op2
24: ....choices
25: .....Albert
26: .....Nicole
28: .....Lizeth