我在一个名为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。
有人可以帮助我吗?
答案 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
个文件我制作了几份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)
请勿尝试使用bash
,grep
,sed
或awk
解析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
注意:
xmlstarlet
,xmllint
或其他支持XML的工具对于正确操作至关重要:否则,您的代码无法忽略任何SampleResult
例如,在评论或CDATA部分中。read -r new_name < <(...)
代替new_name=$(...)
仅捕获第一行输出,因此如果文件有多个名称,我们会跳过除第一行之外的所有名称。--
中使用引号和mv -- "$old_name" "$new_name"
可确保将名称解析为名称,即使它以短划线开头,包含空格或小球等。 POSIX utility syntax guidelines,条目#10。