我需要隐藏所有被拒绝的权限消息:
find . > files_and_folders
我正在尝试这样的消息出现。我需要收集所有不会出现的文件夹和文件。
是否可以将权限级别files_and_folders
到files_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
适用于: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=C
( LC_ALL=C find ...
)以确保报告英文消息,以便grep -v 'Permission denied'
按预期工作。但是,任何显示的错误消息都将以英语显示。
如果您的shell 是bash
或zsh
,那么只需使用符合 POSIX 标准的find
功能 , 这个解决方案非常强大且相当简单 ; 虽然bash
本身不是 POSIX 的一部分,但大多数现代 Unix 平台都附带它,使这个解决方案可以广泛移植:
find . > files_and_folders 2> >(grep -v 'Permission denied' >&2)
注意: 在 find
完成后 ,某些grep
的输出可能会到达,因为整个命令不会等待>(...)
内的命令完成。在bash
,您可以通过附加| cat
来防止这种情况| cat
对命令。
>(...)
是一个(很少使用的) 输出 进程替换 ,允许将输出(在这种情况下, stderr输出( 2>
)重定向到>(...)
内的命令的 stdin。
除了bash
和zsh
, ksh
原则上也支持它们,但是尝试将它们与stderr 的重定向结合起来,就像在这里完成的那样( 2> >(...)
),似乎被默默地忽略(在ksh 93u+
) 。
grep -v 'Permission denied'
过滤掉 ( -v
)包含短语Permission denied
所有行(来自find
命令的 stderr 流),并将剩余的行输出到 stderr( >&2
)。 这种方法是:
robust : grep
仅应用于错误消息 (而不是文件路径和错误消息的组合,可能导致误报),并且除了权限拒绝之外的错误消息将传递给 stderr。
无副作用 : find
的退出代码被保留:无法访问文件系统项目中的至少一个遇到的退出码结果1
(尽管这不会告诉你比许可被拒绝那些其他错误是否发生了(太) )。
完全符合 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 报告非许可拒绝错误,而是将它们捕获到输出文件中的输出路径。