【问题标题】:List directories in Linux based on inclusion and exclusion of specific files根据特定文件的包含和排除列出 Linux 中的目录
【发布时间】:2017-01-17 22:17:46
【问题描述】:

短版:

我正在尝试编写一个 bash 命令,该命令将根据某些文件的存在和/或不存在生成子目录列表。如果目录名称包含名为“Ready”的文件并且不包含名为“Complete”或“Failed”的文件,则该目录名称将包含在列表中。根据我在这里看到的示例,我一直在使用“查找”命令,但我没有足够好的掌握它或一般的 bash 以使其工作。

find . -maxdepth 1 -name Ready | find -mindepth 1 -maxdepth 1 -type d '!' -exec test -e "{}/Complete" ';' -print | find -mindepth 1 -maxdepth 1 -type d '!' -exec test -e "{}/Failed" ';' -print

长版:

在我们的系统中,另一组丢弃了由我们的一个应用程序处理的文件目录(“包”)。这些目录可以包含一个或多个零长度状态文件,这些文件指定捆绑包已准备好进行处理(“就绪”)或应被忽略,因为它已成功处理(“已完成”)或先前存在错误(“失败” ")。

大部分系统都是购买的软件,我们开始开发一些本土的监控、管理和指标收集工具。我正在尝试编写一个脚本,该脚本将在任何给定时间查看这些目录,并根据状态文件的存在与否确定其中哪些已准备好进行处理,哪些将被忽略。

【问题讨论】:

  • 管道findfind 没有意义。使用一个 find 和多个 -exec 语句代替。

标签: linux bash directory find


【解决方案1】:

假设您使用 bash 4 或更高版本,我将跳过 find 并遍历递归 glob **/*/

shopt -s globstar nullglob
for d in **/*/; do
  [[ -e $d/Ready ]] || continue  # Skip directories without a Ready file
  [[ -e $d/Completed ]] && continue  # Skip directories with a Completed file
  [[ -e $d/Failed ]] && continue  # Skip directories with a Failed file
  print '%s\n' "$d"  # If you made it this far, print the directory name
done

这可以浓缩为

shopt -s globstar nullglob
for d in **/*/; do
  [[ -e $d/Ready && ! (-e $d/Completed || -e $d/Failed) ]] && printf '%s\n' "$d"
done

您也可以使用 glob 来识别那些包含 Ready 的目录:

for f in **/*/Ready; do
  d=${f%Ready}
  [[ -e $d/Completed || -e $d/Failed ]] || printf '%s\n' "$d"
done

【讨论】:

  • 效果很好。一个问题——在我们实施某种数据保留策略之前,子目录中可能有很多文件需要递归,这可能会使脚本运行的时间比我想要的快速实用程序要长。我们只需要从起点往下看一级目录,任何低于该目录的内容都可以忽略。有什么办法吗?
  • 在这种情况下,您可以只使用*/*/ 而不是**/*,并且您不需要globstar 选项(这将适用于所有版本的bash,而不是只有 4+)。
  • 删除“globstar”选项并使用单个“*”对我有用(*/*/ 没有)。感谢帮助!
【解决方案2】:

您可以使用findnot 匹配某些名称的选项:

find . -maxdepth 2 -path "*Ready*" ! -name "Failed" -a ! \
-name "Complete" -exec bash -c 'echo "$0"' {} \;

在嵌套目录中,-path 只会在“就绪”目录中查找不包含 (!)“失败”或“完成”的文件。例如:

$ ls
Complete Failed   Ready    outdir   sub1     sub2     sub3 

$ cd Ready ; ls
Complete Failed   Ready    somefile

在父目录中使用上面的find 命令会产生:

./Ready
./Ready/Ready
./Ready/somefile

如果您将-path 切换为-name,您会得到:

./Ready
./Ready/Ready

find 是一个功能强大的实用程序,可以进行调整以适应几乎任何搜索需求。

【讨论】:

    【解决方案3】:

    这很简单。

    find 命令开始,该命令会查找您用作触发器的文件。将其导入一个“grep”,它将删除文件名、排序、消除重复项,例如:

    find . -type f -name Ready -o -name Completed -o -name Failed | grep -o "^.*/" | sort | uniq
    

    -type f 之前添加-maxdepth 2 -mindepth 2 以将深度限制为1 级。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-04
      • 1970-01-01
      • 2018-04-17
      • 2014-09-03
      • 2018-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多