问题描述
我需要隐藏来自:
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.
是否可以将权限级别定向到 files_and_folders
文件?
Is it possible to direct the permission levels to the files_and_folders
file?
如何同时隐藏错误?
推荐答案
注意:
- 这个答案可能比用例更深入,
find 2>/dev/null
在许多情况下可能已经足够了.从跨平台的角度来看,它可能仍然对某些高级 shell 技术的讨论感兴趣,以便找到尽可能健壮的解决方案,即使所防范的情况可能在很大程度上是假设的.
- 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.
如果您的 shell 是 bash
或 zsh
,则有一个强大而简单的解决方案,仅使用符合 POSIX 的 find
功能;虽然 bash
本身不是 POSIX 的一部分,但大多数现代 Unix 平台都带有它,这使得该解决方案具有广泛的可移植性:
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)
注意:
如果您的系统配置为显示本地化错误消息,请在下面的
find
调用前加上LC_ALL=C
(LC_ALL=C find ...
) 确保英文消息被上报,这样grep -v 'Permission denied'
按预期工作.但是,确实显示的任何错误消息总是会以英文显示.
If your system is configured to show localized error messages, prefix the
find
calls below withLC_ALL=C
(LC_ALL=C find ...
) to ensure that English messages are reported, so thatgrep -v 'Permission denied'
works as intended. Invariably, however, any error messages that do get displayed will then be in English as well.
>(...)
是(很少使用)输出 进程替换 允许将输出(在这种情况下,stderr 输出(2>
)重定向到 2>
中命令的 stdin代码>>(...).
除了bash
和zsh
,ksh
也支持原则,但尝试将它们与重定向结合起来来自 stderr,就像这里所做的一样 (2> >(...)
),似乎被默默忽略了(在 ksh 93u+
中).
>(...)
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'
过滤 out (-v
) 所有行(来自find
命令的 stderr 流)包含短语Permission denied
并将剩余的行输出到 stderr (>&2
).
grep -v 'Permission denied'
filters out (-v
) all lines (from thefind
command's stderr stream) that contain the phrasePermission denied
and outputs the remaining lines to stderr (>&2
).
注意:grep
的某些输出可能会在 find
完成后到达,因为整个命令不等待 >(...)
中的命令完成.在 bash
中,您可以通过附加 | 来防止这种情况发生.cat
到命令.
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.
这种方法是:
强大:
grep
仅适用于错误消息(而不适用于文件路径和错误消息的组合,可能导致误报),并将除权限被拒绝以外的错误消息传递给 stderr.
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.
无副作用:find
的退出代码被保留:无法访问遇到的至少一个文件系统项目导致退出代码1
(虽然这不会告诉你是否发生了除权限被拒绝以外的错误(也)).
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 的解决方案要么有局限性,要么需要额外的工作.
Fully POSIX-compliant solutions either have limitations or require additional work.
如果 find
的输出无论如何都要在 file 中捕获(或完全抑制),那么基于管道的解决方案来自Jonathan Leffler 的回答简单、稳健且符合 POSIX:
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
请注意重定向的顺序很重要:2>&1
必须先.
Note that the order of the redirections matters: 2>&1
must come first.
预先在文件中捕获 stdout 输出允许 2>&1
通过管道发送仅错误消息,grep
可以然后明确地操作.
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.
唯一的缺点是整体退出代码将是 grep
命令的,而不是 find
的,在这种情况下意味着:如果根本没有没有错误或只有权限被拒绝的错误,退出代码将是1
(信号failure),否则(除权限被拒绝的错误之外的错误)0
- 这与意图相反.
也就是说,find
的退出代码无论如何都很少使用,因为除了基本失败之外,它通常传达的信息很少,例如传递不存在的路径.
然而,即使只有某些输入路径由于缺乏权限而无法访问的特定情况反映在find
的退出代码中(在 GNU 和 BSD 中 find
):如果处理的 任何 文件发生权限被拒绝错误,则退出代码设置为 1
.
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
.
以下变体解决了:
find . 2>&1 >files_and_folders | { grep -v 'Permission denied' >&2; [ $? -eq 1 ]; }
现在,退出代码指示是否发生任何错误除了 Permission denied
:1
如果是,0
否则.
换句话说:退出代码现在反映了命令的真实意图:如果根本没有错误或仅发生权限拒绝错误,则报告成功 (0
).
这可以说比仅仅传递 find
的退出代码更好,就像顶部的解决方案一样.
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 在评论中提出了一个(仍然符合 POSIX 标准)使用复杂的解决方案的泛化重定向,它即使在将文件路径打印到stdout的默认行为下也能工作:
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
简而言之:自定义文件描述符3
用于临时交换stdout(1
)和stderr(2
),以便错误信息单独可以通过标准输出通过管道传送到grep
.
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.
如果没有这些重定向,数据(文件路径)和错误消息将通过标准输出通过管道传送到 grep
,然后 grep
将不会能够区分错误消息 Permission denied
和一个(假设的)文件,其名称恰好包含短语Permission denied代码>.
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
.
然而,在第一个解决方案中,报告的退出代码将是 grep
的,而不是 find
的,但可以应用与上述相同的修复.
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.
关于 Michael Brux 的回答,
find 有几点需要注意.!-可读 -prune -o -print
:
它需要 GNU
find
;值得注意的是,它不适用于 macOS.当然,如果您只需要使用 GNUfind
的命令,这对您来说不是问题.
It requires GNU
find
; notably, it won't work on macOS. Of course, if you only ever need the command to work with GNUfind
, this won't be a problem for you.
一些Permission denied
错误可能仍然浮出水面:find !-readable -prune
为当前用户确实具有 r
权限但缺少 x
的目录的 child 项报告此类错误>(可执行)权限.原因是因为目录本身是可读的,-prune
没有被执行,并且尝试下降进入那个目录然后触发错误消息.也就是说,典型情况是 r
权限丢失.
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:
- 如果您将权限拒绝错误消息的过滤概念化为一个单独任务,您希望能够将其应用于任何
find
命令,那么主动防止权限拒绝错误的相反方法需要引入噪音";进入find
命令,这也引入了复杂性和逻辑陷阱. - 例如,对 Michael 的回答(截至撰写本文时)投票最多的评论试图展示如何通过包含
-name
过滤器来扩展命令,如下:
查找.!-可读 -prune -o -name '*.txt'
然而,这没有按预期工作,因为需要尾随的-print
操作(可以在).这种微妙之处可能会引入错误.
- 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 thefind
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.
Jonathan Leffler 的回答中的第一个解决方案,find .2>/dev/null >files_and_folders
,正如他自己所说的那样,盲目地消除所有错误消息(而且解决方法很麻烦,而且不完全可靠,他还解释说).实际上,然而,这是最简单的解决方案,因为您可能满足于假设任何和所有错误都与权限相关.
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 的答案,sudo find .>files_and_folders
,简洁实用,但出于安全原因,除了打印文件名之外,不建议用于任何其他事情:因为您作为运行>root 用户,您可能会因 find 或恶意版本中的错误或错误的调用而导致整个系统陷入混乱,这会意外地写入某些内容,如果您以正常权限运行,则不会发生这种情况";(来自 tripleee 对雾的回答的评论).
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).
viraptor 的答案中的第二个解决方案,find .2>&1 |grep -v '权限被拒绝' >some_file
冒着误报的风险(由于通过管道发送 stdout 和 stderr 的混合),并且可能不会通过 stderr 报告非-permission-denied 错误,而是捕获它们与输出文件中的输出路径一起.
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.
这篇关于如何排除所有“权限被拒绝"?来自“查找"的消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!