Bash 从目录中递归地检查内容和移动文件

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

我有一个名为like的目录,其中包含标题和有效负载xml文件(没有.xml扩展名):

我需要检查头文件是否包含两个属性,如果存在这两个属性,则该文件应与其有效负载文件一起移动到另一个目录。 我使用xmllint--xpath来检查属性,它有一个标记,里面有一堆标记,我的查询:

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)
'