如何排除所有“被拒绝的权限”来自“查找”的消息? [英] How can I exclude all "permission denied" messages from "find"?

查看:135
本文介绍了如何排除所有“被拒绝的权限”来自“查找”的消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从

 查找隐藏所有拒绝权限的邮件。 > files_and_folders 

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



可以将权限级别指向 files_and_folders 文件吗?



如何在同一时间隐藏错误?

解决方案

注意:

*这个答案可能比用例权限更深,而 find 2> / dev / null 可能够够好在许多情况下。跨平台观点可能仍然感兴趣,并讨论一些先进的外壳技术,以便找到尽可能强大的解决方案,尽管防范的情况可能在很大程度上是假设的。

* 如果您的系统配置为显示本地化错误消息,请在前面找到以下 LC_ALL = C LC_ALL = C find ... )以确保报告英文 ,所以 grep -v'Permission denied'按照预期工作。然而,始终会显示 所显示的任何错误消息,也将是英文。



如果您的 shell是 bash zsh ,使用仅符合POSIX的查找功能;而 bash 本身不是POSIX的一部分,大多数现代化的Unix平台都配有它,使得该解决方案广泛移植:

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

注意:在 find 完成后,某些 grep 的输出可能会到达,因为整体命令不等待>(...)中的命令完成。在 bash 中,您可以通过追加 | cat to the command。




  • > ...)是(很少使用)输出 过程替代,允许将输出(在这种情况下, stderr 输出( 2> )重定向到$ $ c $内的命令的标准c>>(...)。

    除了 bash zsh ksh 原则上也支持它们,但是尝试将它们与 stderr 的重定向组合起来,就像这样完成( 2>>(...))似乎被忽略(在 ksh 93u + )。 / p>


    • grep -v'Permission denied' filters out -v )包含短语的所有行(来自 find 命令的stderr流)允许被拒绝并将其余行输出到stderr(>& 2 )。

    / li>


这种方法是:




  • 强壮 grep 仅适用于错误消息(而不是文件路径和错误消息的组合,可能导致误报)以及除了被拒绝之外的错误消息


  • 副作用免费 find 的退出代码被保留:无法访问遇到的文件系统项目中的至少一个会导致退出代码 1 (尽管这不会告诉你错误<







符合POSIX的解决方案:



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



如果找到的输出将被 (或完全抑制)然后是基于管道的解决方案n来自 Jonathan Leffler的回答是简单,健壮和符合POSIX的:

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

请注意,重定向的顺序很重要: 2>& 1 必须先



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



唯一的缺点是,整体退出代码将是 grep 命令的,而不是找到,这在这种情况下意味着:如果有所有的错误或仅限于权限被拒绝的错误,退出代码将为 1 (信令失败),否则(错误除了被拒绝的错误) 0 - 这是意图的相反。

说,发现的退出代码很少被使用,因为它经常传达超出基本失败的信息例如传递不存在的路径。

但是,由于缺少权限,输入路径的某些的某些不可访问的具体情况是反映在中找到的退出代码(在GNU和BSD find 中):如果发生权限被拒绝的错误对于处理的文件的任何,退出代码设置为 1



以下变体涉及:

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

现在,退出代码表示是否有 权限被拒绝发生: 1 如果是, 0 否则。 >
换句话说:退出代码现在反映了命令的真正意图:成功( 0 )被报告,如果没有任何错误或只有权限被拒绝的错误发生。

这可以说比通过找到的退出代码更好,如解决方案






在评论中提出使用复杂的重定向对此解决方案进行泛化(仍然符合POSIX标准),即使将打印文件路径的默认行为 stdout

  {find。 3& 2 2>& 1>< 3> grep -v'Permission denied'>& 3; } 3>& 2 2>&$ 1 

简而言之:自定义文件描述符 3 用于临时交换stdout( 1 )和stderr( 2 ) ,以便单独的错误消息可以通过标准输出管道传输到 grep



没有这些重定向,数据(文件路径)错误消息将通过标准输出管道传输到 grep ,而 grep 将无法区分错误消息 权限被拒绝和名称发生的(假设)文件包含短语权限被拒绝



然而,在第一个解决方案中,退出代码报告将是 grep 的,而不是找到,但是可以应用与上述相同的修复程序。


    li>

    有一些关于 Michael Brux的回答 find。 ! -readable -prune -o -print




    • 它需要 GNU 找到;特别是,它不会在macOS上工作。当然,如果你只需要命令与GNU find 一起使用,这对你来说不是一个问题。


    • 某些权限被拒绝错误可能仍然表面: find! - 可读-prune 报告当前用户具有 r 权限的目录的项目的错误,但缺少 x (可执行)权限。原因是因为目录本身 可读, -prune 不会执行,并且尝试将下载到该目录然后触发错误消息。也就是说,典型的案例是 r 的权限丢失。


    • 注意:以下几点是一个哲学和/或具体用例,你可能会认为这与你无关,而且这个命令很适合你的需求,特别是如果简单的打印路径就是您所做的一切:




      • 如果概念化过滤权限被拒绝的错误消息a 单独的任务,您可以应用于 find 命令,那么主动地阻止权限被拒绝的错误需要在 find 命令中引入噪音,这也引入了复杂性和逻辑错误。 >
      • 例如,最高评价的Michael答案(在撰写本文时)试图通过包含来展示如何扩展命令, -name 过滤器,如下所示:

        find。 ! -readable -prune -o -name'* .txt'

        但是,这不是不按照预期工作,因为尾随 -print action is required (可以在这个答案)。



  • 中的第一个解决方案href =https://stackoverflow.com/a/762360/45375> Jonathan Leffler的回答 find。 2> / dev / null>就像他自己所说的那样,盲目地沉默所有错误信息(而且解决方法是麻烦的,并不完全强壮,正如他也解释的)。 实际上,这是最简单的解决方案,因为您可能会认为任何和所有错误都将与权限相关。


  • mist的答案 sudo find。 > files_and_folders 简洁而务实,但出于安全考虑,除了仅仅是打印文件名之外的其他任何东西都是不好的,因为您正在运行用户,您有可能使您的整个系统被找到或恶意版本的错误,或者错误的调用,意外写入的东西,如果你正常运行这不会发生权限(来自对 tripleee 的雾的回答的评论)。


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



I need to hide all permission denied messages from:

find . > files_and_folders

I am experimenting when such message arises. I need to gather all folders and files, to which it does not arise.

Is it possible to direct the permission levels to the files_and_folders file?

How can I hide the errors at the same time?

解决方案

Note:
* This answer probably goes deeper than the use case warrants, and find 2>/dev/null may be good enough in many situations. It may still be of interest for a cross-platform perspective and for its discussion of some advanced shell techniques in the interest of finding a solution that is as robust as possible, even though the cases guarded against may be largely hypothetical.
* If your system is configured to show localized error messages, prefix the find calls below with LC_ALL=C (LC_ALL=C find ...) to ensure that English messages are reported, so that grep -v 'Permission denied' works as intended. Invariably, however, any error messages that do get displayed will then be in English as well.

If your shell is bash or zsh, there's a solution that is robust while being reasonably simple, using only POSIX-compliant find features; while bash itself is not part of POSIX, most modern Unix platforms come with it, making this solution widely portable:

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

Note: There's a small chance that some of grep's output may arrive after find completes, because the overall command doesn't wait for the command inside >(...) to finish. In bash, you can prevent this by appending | cat to the command.

  • >(...) is a (rarely used) output process substitution that allows redirecting output (in this case, stderr output (2>) to the stdin of the command inside >(...).
    In addition to bash, and zsh, ksh supports them as well in principle, but trying to combine them with redirection from stderr, as is done here (2> >(...)), appears to be silently ignored (in ksh 93u+).

    • grep -v 'Permission denied' filters out (-v) all lines (from the find command's stderr stream) that contain the phrase Permission denied and outputs the remaining lines to stderr (>&2).

This approach is:

  • robust: grep is only applied to error messages (and not to a combination of file paths and error messages, potentially leading to false positives), and error messages other than permission-denied ones are passed through, to stderr.

  • side-effect free: find's exit code is preserved: the inability to access at least one of the filesystem items encountered results in exit code 1 (although that won't tell you whether errors other than permission-denied ones occurred (too)).


POSIX-compliant solutions:

Fully POSIX-compliant solutions either have limitations or require additional work.

If find's output is to be captured in a file anyway (or suppressed altogether), then the pipeline-based solution from Jonathan Leffler's answer is simple, robust, and POSIX-compliant:

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

Note that the order of the redirections matters: 2>&1 must come first.

Capturing stdout output in a file up front allows 2>&1 to send only error messages through the pipeline, which grep can then unambiguously operate on.

The only downside is that the overall exit code will be the grep command's, not find's, which in this case means: if there are no errors at all or only permission-denied errors, the exit code will be 1 (signaling failure), otherwise (errors other than permission-denied ones) 0 - which is the opposite of the intent.
That said, find's exit code is rarely used anyway, as it often conveys little information beyond fundamental failure such as passing a non-existent path.
However, the specific case of even only some of the input paths being inaccessible due to lack of permissions is reflected in find's exit code (in both GNU and BSD find): if a permissions-denied error occurs for any of the files processed, the exit code is set to 1.

The following variation addresses that:

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

Now, the exit code indicates whether any errors other than Permission denied occurred: 1 if so, 0 otherwise.
In other words: the exit code now reflects the true intent of the command: success (0) is reported, if no errors at all or only permission-denied errors occurred.
This is arguably even better than just passing find's exit code through, as in the solution at the top.


gniourf_gniourf in the comments proposes a (still POSIX-compliant) generalization of this solution using sophisticated redirections, which works even with the default behavior of printing the file paths to stdout:

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

In short: Custom file descriptor 3 is used to temporarily swap stdout (1) and stderr (2), so that error messages alone can be piped to grep via stdout.

Without these redirections, both data (file paths) and error messages would be piped to grep via stdout, and grep would then not be able to distinguish between error message Permission denied and a (hypothetical) file whose name happens to contain the phrase Permission denied.

As in the first solution, however, the the exit code reported will be grep's, not find's, but the same fix as above can be applied.


Notes on the existing answers:

  • There are several points to note about Michael Brux's answer, find . ! -readable -prune -o -print:

    • It requires GNU find; notably, it won't work on macOS. Of course, if you only ever need the command to work with GNU find, this won't be a problem for you.

    • Some Permission denied errors may still surface: find ! -readable -prune reports such errors for the child items of directories for which the current user does have r permission, but lacks x (executable) permission. The reason is that because the directory itself is readable, -prune is not executed, and the attempt to descend into that directory then triggers the error messages. That said, the typical case is for the r permission to be missing.

    • Note: The following point is a matter of philosophy and/or specific use case, and you may decide it is not relevant to you and that the command fits your needs well, especially if simply printing the paths is all you do:

      • If you conceptualize the filtering of the permission-denied error messages a separate task that you want to be able to apply to any find command, then the opposite approach of proactively preventing permission-denied errors requires introducing "noise" into the find command, which also introduces complexity and logical pitfalls.
      • For instance, the most up-voted comment on Michael's answer (as of this writing) attempts to show how to extend the command by including a -name filter, as follows:
        find . ! -readable -prune -o -name '*.txt'
        This, however, does not work as intended, because the trailing -print action is required (an explanation can be found in this answer). Such subtleties can introduce bugs.
  • The first solution in Jonathan Leffler's answer, find . 2>/dev/null > files_and_folders, as he himself states, blindly silences all error messages (and the workaround is cumbersome and not fully robust, as he also explains). Pragmatically speaking, however, it is the simplest solution, as you may be content to assume that any and all errors would be permission-related.

  • mist's answer, sudo find . > files_and_folders, is concise and pragmatic, but ill-advised for anything other than merely printing filenames, for security reasons: because you're running as the root user, "you risk having your whole system being messed up by a bug in find or a malicious version, or an incorrect invocation which writes something unexpectedly, which could not happen if you ran this with normal privileges" (from a comment on mist's answer by tripleee).

  • The 2nd solution in viraptor's answer, find . 2>&1 | grep -v 'Permission denied' > some_file runs the risk of false positives (due to sending a mix of stdout and stderr through the pipeline), and, potentially, instead of reporting non-permission-denied errors via stderr, captures them alongside the output paths in the output file.

这篇关于如何排除所有“被拒绝的权限”来自“查找”的消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆