【问题标题】:Checking content and moving files recursively from a directory从目录递归检查内容和移动文件
【发布时间】:2021-04-27 13:01:22
【问题描述】:

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

File1
File1_PAYLOAD
File2
File2_PAYLOAD

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

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 查询工作正常,并根据属性是否存在返回真/假。问题在于如何仅迭代头文件并移动它们。我尝试使用 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 find,这样我就可以合并某种 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'

我从https://unix.stackexchange.com/questions/321697/why-is-looping-over-finds-output-bad-practice/321753#321753看到的这个语法

【问题讨论】:

    标签: bash shell unix xpath


    【解决方案1】:

    也许你可以试试下面,请检查这是否适合你:

    #!/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
    
        
    

    【讨论】:

    • 嗨,您给定的代码给出了错误:警告:无法加载外部实体“文件名”——这里显示的这个文件名没有前面的实际路径,因此我的 xpath 不能作为它需要文件的完整路径,因为当我尝试回显它时 stat 为空。尝试删除 basename 属性以获取完整路径,但随后出现错误:find 'FILENAME-with full path':权限被拒绝。如果我用简单的“-exec echo {}”替换“-exec basename”{}“”,它工作正常 感谢语法☺。
    • @KushalSharma:很高兴它对你有用!我相信只是为了降低复杂性,您可以将find 替换为:for i in /tmp/files/*_PAYLOAD; do .......done...也许您可以尝试,它应该可以工作。谢谢!
    • 我也试过了,下一个发布的解决方案只是基于它,这是一个非常干净和简单的解决方案,我只能理解这是什么 -> [[ -e "$f" ]] || continue 正在做。
    【解决方案2】:

    已编辑

    另一个采取它 -
    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
    

    【讨论】:

    • 即使 xpath 返回 false 也会移动文件,我刚刚开始编写脚本不知道如何修剪“PAYLOAD”并使用其余的字符串。你能解释一下这是做什么的吗:[[ -e "$f" ]] ||继续谢谢。
    • 保存了 xmllint 在变量中返回的内容并添加了一个 IF 条件,然后它就可以正常工作了。
    • 正如我所说,假设 return 设置了退出代码。显然没有。已编辑。
    【解决方案3】:

    通过使用(及其集成的EXPath File Module)而不是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)
    '
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2015-03-01
      • 2011-02-28
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多