Bash 从目录中递归地检查内容和移动文件
我有一个名为like的目录,其中包含标题和有效负载xml文件(没有.xml扩展名): 我需要检查头文件是否包含两个属性,如果存在这两个属性,则该文件应与其有效负载文件一起移动到另一个目录。 我使用xmllint--xpath来检查属性,它有一个头标记,里面有一堆头标记,我的查询:Bash 从目录中递归地检查内容和移动文件,bash,shell,unix,xpath,xidel,Bash,Shell,Unix,Xpath,Xidel,我有一个名为like的目录,其中包含标题和有效负载xml文件(没有.xml扩展名): 我需要检查头文件是否包含两个属性,如果存在这两个属性,则该文件应与其有效负载文件一起移动到另一个目录。 我使用xmllint--xpath来检查属性,它有一个头标记,里面有一堆头标记,我的查询: xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value
xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value='AAAA'] and *[local-name()='header'][@name='Update' and @value='DONE']])
xpath查询工作正常,并根据属性是否存在返回true/false。问题在于如何只遍历头文件并移动它们。我尝试过使用find,比如:
#!/bin/bash
dest="/tmp/proc"
loc="/tmp/files"
find $loc -maxdepth 1 -mindepth 1 ! -name '*_PAYLOAD' -exec xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value='AAAA'] and *[local-name()='header'][@name='Update' and @value='DONE']]) " {} \; -exec mv {} $dest \; -exec mv {}_PAYLOAD $dest \;
但是这个查询会移动文件,即使我的xpath查询返回false,我认为find-exec可能会将返回的true/false作为字符串,因此返回true,并继续执行下一个exec。所以我尝试用sh-c查找,这样我就可以合并某种if和else结构:
#!/bin/bash
dest="/tmp/proc"
loc="/tmp/files"
find $loc -maxdepth 1 -mindepth 1 ! -name '*_PAYLOAD' -exec sh -c '
for file do
stat=$(xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value='AAAA'] and *[local-name()='header'][@name='Update' and @value='DONE']]) " "$file" | grep 'true' | wc -l)
if [ "$stat" -eq 1 ]
mv "$file" "$dest"
mv "$file"_PAYLOAD "$dest"
done' sh {} \;
但这会产生一个错误:
sh: -c: line 6: syntax error near unexpected token `done' sh: -c: line 6: `done'
这是我在中看到的语法。也许您可以在下面尝试,请检查这是否适用于您:
#!/bin/bash
dest="/tmp/proc"
loc="/tmp/files"
for i in $(find "$loc" -maxdepth 1 -mindepth 1 ! -name "*_PAYLOAD" -exec basename "{}" \;)
do
stat=$(xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value='AAAA'] and *[local-name()='header'][@name='Update' and @value='DONE']]) "$i"
if [[ "$stat" == "true" ]]
then
mv "$i" "$dest"
mv "$i"_PAYLOAD "$dest"
fi
done
编辑
另一种看法-xmllint
显然不返回该布尔值作为其退出代码,而且非常难看,因此我将其分配给了一个函数
tst() { xmllint --xpath "boolean(//*[local-name()='headers' and *[local-name()='header'][@name='Type' and @value='AAAA'] and *[local-name()='header'][@name='Update' and @value='DONE']])" "$1"; }
for p in /tmp/files/*_PAYLOAD
do f=${p%_PAYLOAD}
[[ -e "$f" && true == "$(tst $f)" ]] && mv $f $p /tmp/proc
done
通过使用(及其集成)而不是xmllint
,我相信根本不需要Bash脚本
xidel -s --xquery '
let $dest:="/tmp/proc/",
$loc:="/tmp/files/"
for $x in file:list($loc,false(),"*_PAYLOAD")
where doc($loc||$x)//*[
local-name()="headers" and
*[local-name()="header"][@name="Type" and @value="AAAA"] and
*[local-name()="header"][@name="Update" and @value="DONE"]
]
return
file:move($loc||$x,$dest||$x)
'
您好,您给定的代码给出了错误:警告:未能加载外部实体“FILENAME”-此处显示的文件名之前没有实际路径,因此我的xpath无法工作,因为它需要文件的完整路径,因为我尝试回显时stat为空。试图删除basename属性以获取完整路径,但出现错误:查找“具有完整路径的文件名”:权限被拒绝。如果我用一个简单的“-exec echo{}”替换“-exec basename”{}”,效果很好,谢谢语法☺.@库沙尔玛:很高兴它对你有用!我相信,为了降低复杂性,您可以将
find
替换为:for I in/tmp/files/*\u有效载荷;完成……完成
…也许你可以尝试一下,它应该会起作用。谢谢我也尝试过,发布的下一个解决方案仅基于此,这是一个非常干净和简单的解决方案,我只是能够理解这个->[[-e“$f”]]| | continue在做什么。这是移动文件,即使xpath返回false,我刚刚开始编写脚本,不知道如何修剪“负载”并使用字符串的其余部分。你能解释一下这是怎么做的吗:[-e“$f”]| |继续谢谢你。保存xmllint在变量中返回的内容并添加IF条件,然后它就可以正常工作了。正如我所说,假设返回设置退出代码。显然没有。编辑。
xidel -s --xquery '
let $dest:="/tmp/proc/",
$loc:="/tmp/files/"
for $x in file:list($loc,false(),"*_PAYLOAD")
where doc($loc||$x)//*[
local-name()="headers" and
*[local-name()="header"][@name="Type" and @value="AAAA"] and
*[local-name()="header"][@name="Update" and @value="DONE"]
]
return
file:move($loc||$x,$dest||$x)
'