Bash: 查找排除目录错误

Bash: Find exclude directory error

我有这个文件夹结构:

incoming/
Printing/
    |------ done/
    \------ error/

服务器正在监视 Printing 文件夹,等待 .txt 文件出现在其中。当检测到新文件时,它会将其发送到打印机并在成功时将文件移动到 done 或在失败时移动到 error

我正在处理的脚本必须执行以下操作:扫描 incoming 目录中的文件,并将它们一个一个地传输到 Printing 文件夹中。我从在 Whosebug 上找到的这个脚本开始:

#!/usr/bin/env bash

while true; do
  target="/var/www/test";
  dest="/var/www/incoming";

  find $dest -maxdepth 1 -type f | sort -r | while IFS= read -r file; do
    counter=0;
    while [ $counter -eq 0 ]; do
      if find   "$target" -maxdepth 0 -mindepth 0 -empty | read; then 
        mv -v "$file" "$target" && counter=1; 
      else
        echo "Directory not empty: $(find "$target" -mindepth 1)"
        sleep 2; 
      fi;
    done;
  done
done

问题是它检测到两个子文件夹 doneerror 并拒绝复制文件,总是发出 "Directory not empty" 消息。 我需要一种方法让脚本忽略这些文件夹。

我尝试了涉及 -prune! -pathfind 命令的变体,但我没有找到任何有效的方法。如何修复内循环中的 find 命令以按我的要求执行?

有问题的命令是这样的:

find "$target" -maxdepth 0 -mindepth 0 -empty

从认识它的作用开始:

  • 它在由 "$target"
  • 命名的目录(如果有)上运行
  • 因为 -maxdepth 0,它只测试 该路径本身
  • -empty 谓词匹配 常规文件和目录
  • -mindepth 0 是默认值;明确表达它没有任何附加效果)

由于您期望目标目录 永远不会 为空(它将至少包含您描述的两个子目录),因此您需要一种不基于-empty 谓词。 find 无法调整 "empty" 的含义。

有多种方法可以解决这个问题,有些包括 find,有些则没有。由于 find 有点重量级,而且对于复杂测试它的参数语法有点晦涩,我建议使用另一种方法:ls + grep。示例:

# File names to ignore in the target directory
ignore="\
.
..
done
error"

# ...

while /bin/true; do
  files=$(ls -a "$target" | grep -Fxv "$ignore")

  if [ -z "$files" ]; then
    mv -v "$file" "$target"
    break
  else
    # non-ignored file(s) found
    echo "Directory not empty:"
    echo "$files"
    sleep 2
  fi
done

注意事项:

  • -a 选项提供给 ls 以捕获点文件,从而匹配 find-empty 谓词的行为。您可能更愿意忽略点文件,在这种情况下,您可以简单地删除 -a.

  • grepF选项指定匹配固定字符串(不是模式),-x选项告诉它必须匹配整个字符串线。 -v 选项反转了匹配的含义,因此这三个选项一起导致匹配行(文件名)与 ignore 变量中指定的行(文件名)不同。

  • 在变量中捕获文件列表比重新计算它更有效,并且避免了在文件移动之前检测到文件的竞争条件。通过捕获文件列表,您可以确保重述脚本决定延迟所依据的确切数据。

  • 文件名可能包含换行符,精心制作的包含换行符的文件名可能会欺骗此脚本,使该脚本认为目录(实际上)是空的,而实际上它不是。如果这对您来说是一个问题,那么您将需要更强大的东西,也许毕竟使用 find