协慌网

登录 贡献 社区

如何从 “查找” 中排除所有 “权限被拒绝” 的消息?

我需要隐藏所有被拒绝的权限消息:

find . > files_and_folders

我正在尝试这样的消息出现。我需要收集所有不会出现的文件夹和文件。

是否可以将权限级别files_and_foldersfiles_and_folders文件?

如何同时隐藏错误?

答案

使用:

find . 2>/dev/null > files_and_folders

当然,这不仅隐藏了Permission denied错误,还隐藏了所有错误消息。

如果你真的想要保留其他可能的错误,例如符号链接上的跳数太多,而不是允许拒绝的错误,那么你可能不得不猜测你没有很多名为 “权限被拒绝” 的文件并尝试:

find . 2>&1 | grep -v 'Permission denied' > files_and_folders

如果您只想过滤标准错误,可以使用更精细的构造:

find . 2>&1 > files_and_folders | grep -v 'Permission denied' >&2

find命令的 I / O 重定向是: 2>&1 > files_and_folders | 。管道将标准输出重定向到grep命令并首先应用。 2>&1将标准错误发送到与标准输出(管道)相同的位置。 > files_and_folders将标准输出(但不是标准错误)发送到文件。最终结果是写入标准错误的消息沿管道发送,并且find的常规输出被写入文件。 grep过滤标准输出(您可以决定您希望它的选择性,并且可能必须根据区域设置和 O / S 更改拼写),而最后的>&2表示存活的错误消息(写入标准输出)再次转到标准错误。最终的重定向在终端上可以被视为可选的,但在脚本中使用它是一个非常好的主意,以便在标准错误中出现错误消息。

这个主题有无穷无尽的变化,取决于你想做什么。这适用于任何带有任何 Bourne shell 衍生产品(Bash,Korn,...)的 Unix 版本以及任何符合 POSIX 标准的find版本。

如果您希望适应系统上的特定find版本,可能会有其他选择。 GNU find特别具有其他版本中无法提供的无数选项 - 请参阅当前接受的一组选项的答案。

使用:

find . ! -readable -prune -o -print

或更一般地说

find <paths> ! -readable -prune -o <other conditions like -name> -print
  • 避免 “权限被拒绝”
  • 并且不要抑制(其他)错误消息
  • 并获取退出状态 0(“所有文件都已成功处理”)

适用于:find(GNU findutils)4.4.2。背景:

  • -readable测试匹配可读文件。的!当 test 为 false 时,operator 返回 true。而且! -readable匹配不可读的目录(&files)。
  • -prune操作不会进入目录。
  • ! -readable -prune可以翻译为:如果目录不可读,请不要进入。
  • -readable测试考虑了访问控制列表和-perm测试忽略的其他权限假象。

有关更多详细信息,另请参见find (1)联机帮助页

注意:
* 这个答案可能比用例保证更深入,并且在许多情况下find 2>/dev/null可能已经足够好了。对于跨平台的观点以及为了找到尽可能强大的解决方案而讨论一些先进的 shell 技术可能仍然有意义,即使防范的案例可能在很大程度上是假设的。
* 如果您的系统配置为显示本地化的错误消息 ,请在下面的find调用前加上LC_ALL=CLC_ALL=C find ... )以确保报告英文消息,以便grep -v 'Permission denied'按预期工作。但是,任何显示的错误消息将以英语显示。

如果您的shell 是bashzsh ,那么只需使用符合 POSIX 标准的find功能这个解决方案非常强大且相当简单 ; 虽然bash本身不是 POSIX 的一部分,但大多数现代 Unix 平台都附带它,使这个解决方案可以广泛移植:

find . > files_and_folders 2> >(grep -v 'Permission denied' >&2)

注意: find完成 ,某些grep的输出可能会到达,因为整个命令不会等待>(...)内的命令完成。在bash ,您可以通过附加| cat来防止这种情况| cat对命令。

  • >(...)是一个(很少使用的) 输出 进程替换 ,允许将输出(在这种情况下, stderr输出( 2> )重定向到>(...)内的命令的 stdin。
    除了bashzshksh 原则上也支持它们,但是尝试将它们与stderr 的重定向结合起来,就像在这里完成的那样( 2> >(...) ),似乎被默默地忽略(在ksh 93u+ ) 。

    • grep -v 'Permission denied'过滤-v )包含短语Permission denied所有行(来自find命令的 stderr 流),并将剩余的行输出到 stderr( >&2 )。

这种方法是:

  • robustgrep仅应用于错误消息 (而不是文件路径和错误消息的组合,可能导致误报),并且除了权限拒绝之外的错误消息将传递给 stderr。

  • 无副作用find的退出代码被保留:无法访问文件系统项目中的至少一个遇到的退出码结果1 (尽管这不会告诉你比许可被拒绝那些其他错误是否发生了(太) )。


符合 POSIX 标准的解决方案:

完全符合 POSIX 标准的解决方案有限制或需要额外的工作。

如果无论如何都要在文件中捕获find的输出 (或完全被抑制),那么Jonathan Leffler 的答案中基于流水线的解决方案简单,强大且符合 POSIX:

find . 2>&1 >files_and_folders | grep -v 'Permission denied' >&2

注意事项重定向的顺序: 2>&1必须是第一位的

在前面的文件中捕获 stdout 输出允许2>&1 通过管道发送错误消息,然后grep可以明确地操作。

唯一的缺点是整个退出代码将是grep命令 ,而不是find ,在这种情况下意味着:如果根本没有错误或只有权限拒绝错误,退出代码将为1 (信号失败 ) ,否则(权限被拒绝的错误除外) 0 - 这与意图相反。
也就是说,无论如何都很难使用find的退出代码 ,因为它通常会传递除基本故障之外的一些信息,例如传递不存在的路径。
但是,即使只有一些输入路径由于缺少权限而无法访问的特定情况反映在find的退出代码中(在 GNU 和 BSD find ):如果处理的任何文件发生权限被拒绝错误,退出代码设置为1

以下变体解决了以下问题:

find . 2>&1 >files_and_folders | { grep -v 'Permission denied' >&2; [ $? -eq 1 ]; }

现在,退出代码指示是否发生 Permission denied 之外的任何错误: 1如果是,否则为0
换句话说:退出代码现在反映了命令的真实意图:如果没有错误或发生权限拒绝错误,则报告成功( 0 )。
这可以说比传递find的退出代码更好,就像在顶部的解决方案中一样。


评论中的gniourf_gniourf提出了一种(仍然符合 POSIX 标准) 使用复杂重定向来推广此解决方案即使将文件路径打印到stdout的默认行为也是如此

{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1

简而言之:自定义文件描述符3用于临时交换 stdout( 1 )和 stderr( 2 ),因此可以通过 stdout 将错误消息单独传递给grep

如果没有这些重定向,数据(文件路径) 错误消息都将通过 stdout 通过管道输出到grep ,然后grep将无法区分错误消息 Permission denied和一个(假设的) 文件,其名称恰好包含短语Permission denied

然而,与第一个解决方案一样,报告的退出代码将是grep ,而不是find ,但可以应用与上面相同的修复。


关于现有答案的说明:

  • find . ! -readable -prune -o -print 迈克尔布鲁克斯的答案有几点需要注意find . ! -readable -prune -o -print

    • 它需要GNU find ; 值得注意的是,它不适用于 macOS。当然,如果你只需要使用命令来使用 GNU find ,这对你来说不是问题。

    • 一些Permission denied错误可能仍然存在find ! -readable -prune报告当前用户具有r权限但缺少x (可执行)权限的目录的子项目的此类错误。原因是因为目录本身可读的,所以不执行-prune ,然后尝试下降该目录然后触发错误消息。也就是说, 典型的情况是r权限丢失。

    • 注意:以下几点是哲学和 / 或特定用例的问题,您可能认为它与您无关,并且该命令可以很好地满足您的需求,特别是如果您只需要打印路径:

      • 如果您将权限被拒绝错误消息的过滤概念化为您希望能够应用于任何 find命令的单独任务,那么主动防止权限被拒绝错误的相反方法需要在find命令中引入 “noise”,还介绍了复杂性和逻辑缺陷
      • 例如,对迈克尔答案的最高投票评论(截至本文撰写时)试图通过包含-name过滤器来展示如何扩展命令,如下所示:
        find . ! -readable -prune -o -name '*.txt'
        然而,这并不因为后工作打算, -print 需要采取行动(的解释中可以找到这个答案 )。这种微妙之处可能会引入漏洞。
  • find . 2>/dev/null > files_and_folders Jonathan Leffler 的第一个解决方案find . 2>/dev/null > files_and_folders ,正如他自己所说, 盲目地使所有错误消息 find . 2>/dev/null > files_and_folders (并且解决方法很麻烦,并且不完全健壮,正如他也解释的那样)。 从务实角度讲 ,但是,它是最简单解决方案 ,因为你可能会内容承担任何和所有的错误都会被允许相关。

  • 雾的答案sudo find . > files_and_folders简洁实用,但除了打印文件名之外的其他任何内容都是不明智的 ,出于安全原因:因为你是以root用户身份运行,“你冒着整个系统被查找中的错误弄乱的风险一个恶意版本,或一个意外写入的错误调用,如果你以正常的权限运行它,就不会发生这种情况 “(来自对三人的薄雾回答的评论 )。

  • viraptor 的回答find . 2>&1 | grep -v 'Permission denied' > some_file第二个解决方案find . 2>&1 | grep -v 'Permission denied' > some_file存在误报的风险(由于通过管道发送混合的 stdout 和 stderr),并且可能不是通过 stderr 报告许可拒绝错误,而是将它们捕获到输出文件中的输出路径。