Bash脚本,用于在XML文件中搜索字符串,并使用字符串重命名该文件

时间:2018-02-23 10:17:00

标签: bash search

我在一个名为XXXXX.xml的文件夹中有很多报告文件,我需要在每个文件中搜索一个字符串,用特定的字符串重命名该文件,例如:

我有这个名为28022018.xml的文件

<?xml version="1.0" encoding="UTF-8"?>   
<SampleResults XMLCreationDateTime="2018-02-23T10:28:45" XMLVersion="7">
<SampleResult AreReproTestOutliersIgnored="No" ReproTestResult="NotUsed" ReproTestType="None" Instrument="PXC01" MethodName="Fe-91" RecalculationDateTime="2018-02-22T12:26:16" BackupStatus="Original" Origin="Measured" CorrType="None" Type="Unknown" OperatorName="" Name="18-1325">
<SampleIDs>
    <SampleID Type="Text" KeepLastValue="False" MustExist="False" IsReadOnly="False" IsSampleName="True">
        <IDName>Sampe Name</IDName>
        <IDValue>18-1325</IDValue>
        </SampleID>
    <SampleID Type="GradeName" KeepLastValue="True" MustExist="False" IsReadOnly="True" IsSampleName="False">
        <IDName>Grade ID</IDName>
        <IDValue>1.8161 58CrV4</IDValue>
    </SampleID>
    <SampleID Type="Text" KeepLastValue="False" MustExist="False" IsReadOnly="False" IsSampleName="False">
        <IDName>New</IDName>
        <IDValue>Cliente</IDValue>
    </SampleID>
</SampleIDs>
</SampleResult>
</SampleResults>

我需要创建一个脚本,将字符串保存在3行(name =&#34; 18-1325&#34;)中的属性标签NAME中,并使用它将文件从28022018.xml重命名为18 -1325.xml。

有人可以帮助我吗?

4 个答案:

答案 0 :(得分:1)

这样做的速度很快且很脏:

#!/bin/bash

for filename in ./*.xml; do
    echo Checking $filename
    aux1=`grep -oE ' Name=\"(.*)\"' < $filename | cut -f 2 -d '"'`
    cp $filename $aux1.xml
done

echo Done!

基本上它的作用:

  • 迭代当前目录中的所有*.xml个文件
  • 搜索包含&#34;的行名称=&#34;
  • 剪切目标文本并获取XML字段的值
  • 将文件复制到新文件

我制作了几份XML并对其进行了测试(名称应该有不同的值,否则最终会得到一个文件:

$ cat sample1.xml
<?xml version="1.0" encoding="UTF-8"?>
<SampleResults XMLCreationDateTime="2018-02-23T10:28:45" XMLVersion="7">
<SampleResult AreReproTestOutliersIgnored="No" ReproTestResult="NotUsed" ReproTestType="None" Instrument="PXC01" MethodName="Fe-91" RecalculationDateTime="2018-02-22T12:26:16" BackupStatus="Original" Origin="Measured" CorrType="None" Type="Unknown" OperatorName="" Name="18-1325">
<SampleIDs>
    <SampleID Type="Text" KeepLastValue="False" MustExist="False" IsReadOnly="False" IsSampleName="True">
            <IDName>Sampe Name</IDName>
            <IDValue>18-1325</IDValue>
            </SampleID>
    <SampleID Type="GradeName" KeepLastValue="True" MustExist="False" IsReadOnly="True" IsSampleName="False">
            <IDName>Grade ID</IDName>
            <IDValue>1.8161 58CrV4</IDValue>
    </SampleID>
    <SampleID Type="Text" KeepLastValue="False" MustExist="False" IsReadOnly="False" IsSampleName="False">
            <IDName>New</IDName>
            <IDValue>Cliente</IDValue>
    </SampleID>
</SampleIDs>

$ ./script.sh
Checking ./sample1.xml
Checking ./sample2.xml
Done!

$ ls

18-1325.xml
18-1326.xml
sample1.xml
sample2.xml

更新:感谢@Arusekk评论!使用grep -oE使脚本更容易!

答案 1 :(得分:0)

这就是我提出的,如果第3行中的参数数量发生变化,它将起作用。

Victor获取代码灵感并进行修改。

您仍然可以对其进行优化以使其更加美观,特别注意&#34; SampleResult&#34; &#34;名称=&#34;

#!/bin/bash

for filename in ./*.xml; do
    echo "Checking ${filename}"
    new_file_name=$(cat ${filename} | grep 'SampleResult ' | grep 'Name' | awk -F' Name=' '{print $2}' | tr -d '">')
    cp ${filename} ${new_file_name}
done

答案 2 :(得分:0)

请勿尝试使用bashgrepsedawk解析XML。请使用专用工具,例如xmllint,它是Debian上的包xml2-utils的一部分。

name=$(xmllint --xpath 'string(//SampleResult/@Name)' input.xml)
if [ "$name" ]; then
  mv input.xml "$name".xml
fi

BTW:您的XML示例已损坏。 <{1}}和SampleResult的结束标记丢失了。

答案 3 :(得分:0)

另一种方法也使用适当的XML感知工具(在本例中为XMLStarlet):

for f in *.xml; do
  read -r new_name < <(xmlstarlet sel -t -m '//SampleResult[@Name]' -v ./@Name -n <"$f")
  [[ $f ]] && [[ $f != "${new_name}.xml" ]] && mv -- "$f" "$new_name"
done

注意:

  • 使用xmlstarletxmllint或其他支持XML的工具对于正确操作至关重要:否则,您的代码无法忽略任何SampleResult例如,在评论或CDATA部分中。
  • 使用read -r new_name < <(...)代替new_name=$(...)仅捕获第一行输出,因此如果文件有多个名称,我们会跳过除第一行之外的所有名称。
  • --中使用引号和mv -- "$old_name" "$new_name"可确保将名称​​解析为名称,即使它以短划线开头,包含空格或小球等。 POSIX utility syntax guidelines,条目#10。