【问题标题】:Omit something from find if directory has specific file in it如果目录中有特定文件,则从查找中省略某些内容
【发布时间】:2022-01-09 12:49:07
【问题描述】:

我需要打印我所有的数据库配置,我的项目使用 laravel 和 CI 框架。所以简而言之,我正在寻找以下文件。

  • .env → 位于/var/www/example_system/.env
  • database.php → 位于/var/www/example_system/application/config/database.php
  • core_db.php → 位于/var/www/example_system/app/core/core_db.php

我正在使用以下 find 命令来执行此任务。

find /var/www -maxdepth 4 -type f -name ".env" -not \( -path "/var/www/*/config" -prune \) -o -path '*core/*' -name "core_db.php" -o -path '*config/*' -name "database.php"

哪个打印。

/var/www/baloon/app/core/core_db.php
/var/www/infinys/application/config/database.php
/var/www/duffyweb/.env
/var/www/duffyweb/config/database.php
/var/www/loseweb/.env
/var/www/loseweb/config/database.php
/var/www/resto_app/application/config/database.php

但这不能满足我的需要,因为它仍然输出两个

  • /var/www/duffyweb/config/database.php
  • /var/www/loseweb/config/database.php

即使(我认为)我已经在我的 find 命令中使用 -name ".env" -not \( -path "/var/www/*/config" -prune \) 参数明确排除了它。

所以我的问题是如果目录中有特定文件,我如何从查找中排除某些内容。在这种情况下,如果有.env 文件,我想排除 config/database.php,因为我优先考虑.env 而不是database.php

【问题讨论】:

  • notprune 是双重否定。你确定这是你想要的吗?旁注:正如您已经知道文件在哪里,为什么不简单地使用通配符?例如/var/www/*/.env /var/www/*/application/config/database.php /var/www/*/app/core/core_db.php?如果example_system 可以代表多个层次结构级别,您可以启用globstar bash 选项(shopt -s globstar)并在全局模式中将* 替换为**
  • 您不应同时使用 pathname。也许你想要这样的东西:-not -path '*/core/*.php' -not -path '*/config/*.php'
  • @RenaudPacalet 我一直在关注这个answer,是的,实际情况是在/var/www 的20 多个项目中寻找该文件,每个项目至少有.env 和@ 987654347@ 在 1 个项目中,如果项目有 .env 文件,我会尝试排除配置一。
  • @Darkman 谢谢,但我想保留所有其他结果(他们的目录中没有 .env),你的方法阻止了这种可能性。

标签: bash shell find


【解决方案1】:

假设example_system 仅代表一个层次结构级别,如果文件存在,您总是希望打印core_db.php

以下相当复杂的find 命令可能不远了:

find /var/www -maxdepth 4 -type f \( \
  -name .env -o -name core_db.php -o \
  -name database.php -exec sh -c '! [ -f "$(dirname "$1")"/../.env ]' _ "{}" \; \
  \) -print

这个想法是使用-exec 操作为database.php 文件添加条件。该操作是对子shell 的调用,仅当名为.env 的文件在database.php 文件下不存在两个层次结构级别时才会返回true。子shell脚本比较简单:

! [ -f "$(dirname "$1")"/../.env ]

它有一个参数:database.php 文件的路径。它不直接作为-exec 参数调用。而是作为sh -c的脚本参数调用:

sh -c 'script' argv0 argv1...

argv0 对应于脚本的$0 参数(未使用,因此我经常将_ 用作不关心),argv1 对应于$1 位置参数。

但由于它有点复杂,更直接的 bash 循环可能更容易理解和维护:

for d in var/www/*/; do 
  e="${d}.env"
  db="${d}application/config/database.php"
  c="${d}app/core/core_db.php"
  if [ -f "$e" ]; then
    echo "$e"
  elif [ -f "$db" ]; then
    echo "$db"
  fi
  if [ -f "$c" ]; then
    echo "$c"
  fi
done

【讨论】:

  • 谢谢!这实际上有效。您能帮我解释一下-exec 参数吗?为什么会有下划线?
  • 我添加了一个解释。
  • 感谢您的帮助,非常感谢。
  • 您好,我想问一个小问题。在[ -f ] 部分中,是否可以测试超过 1 个匹配项?例如,我的目录有app/core/core_db.phpjbapp/core/core_db.php applv/core/core_db.php,目录结构保持不变,但app 有几个变化。我尝试使用通配符将所有名称与app 匹配,但它不起作用(无输出)。
  • 我是否需要将每个目录名称硬核到 for 循环中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 1970-01-01
  • 2013-08-18
  • 1970-01-01
  • 2017-08-26
相关资源
最近更新 更多