如何从“查找”中排除所有“权限被拒绝”消息?
-
11-09-2019 - |
题
我需要隐藏所有 没有权限 消息来自:
find . > files_and_folders
我正在尝试何时出现此类消息。我需要收集所有不会出现的文件夹和文件。
是否可以将权限级别定向到 files_and_folders
文件?
如何同时隐藏错误?
解决方案
笔记:
*这个答案可能比用例所保证的更深入,并且 find 2>/dev/null
在许多情况下可能就足够好了。尽管所防范的情况在很大程度上可能是假设的,但出于跨平台的角度以及为了找到尽可能强大的解决方案而对一些高级 shell 技术的讨论,它可能仍然令人感兴趣。
* 如果您的系统配置为显示 本地化的 错误信息, ,前缀 find
下面调用 LC_ALL=C
(LC_ALL=C find ...
) 为了保证 英语 消息被报告,以便 grep -v 'Permission denied'
按预期工作。然而,任何错误消息总是 做 显示的内容也将以英文显示。
如果你的 外壳是 bash
或者 zsh
, , 有 一个稳健且相当简单的解决方案, , 使用 仅符合 POSIX 标准 find
特征;尽管 bash
它本身不是 POSIX 的一部分,大多数现代 Unix 平台都附带它,使得这个解决方案具有广泛的可移植性:
find . > files_and_folders 2> >(grep -v 'Permission denied' >&2)
笔记:有一个很小的机会,其中一些 grep
的输出可能到达 后 find
完成,因为整体命令不等待里面的命令 >(...)
完成。在 bash
, ,您可以通过附加来防止这种情况 | cat
到命令。
>(...)
是一个(很少使用) 输出 流程替代 允许重定向输出(在这种情况下, 标准错误 输出 (2>
) 到里面命令的标准输入>(...)
.
此外bash
和zsh
,ksh
也支持他们 原则, ,但尝试将它们与重定向结合起来 标准错误, ,正如这里所做的那样(2> >(...)
),似乎被默默地忽略(在ksh 93u+
).grep -v 'Permission denied'
过滤器 出去 (-v
)所有行(从find
命令的 stderr 流)包含短语Permission denied
并将剩余行输出到 stderr (>&2
).
这种做法是:
强壮的:
grep
仅适用于 错误信息 (而不是文件路径和错误消息的组合,可能导致误报),并且除权限被拒绝之外的错误消息都会传递到 stderr。无副作用:
find
的退出代码被保留:无法访问所遇到的至少一项文件系统项目会导致退出代码1
(尽管这不会告诉你是否有错误 其他 比拒绝许可的情况也发生了)。
符合 POSIX 标准的解决方案:
完全符合 POSIX 标准的解决方案要么有局限性,要么需要额外的工作。
如果 find
的输出将被捕获在 文件 反正 (或完全抑制),然后基于管道的解决方案 乔纳森·莱弗勒的回答 简单、健壮且符合 POSIX 标准:
find . 2>&1 >files_and_folders | grep -v 'Permission denied' >&2
请注意,重定向的顺序很重要: 2>&1
必须来 第一的.
预先捕获文件中的标准输出输出允许 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 标准) 使用复杂的重定向来推广该解决方案, , 哪个 即使使用打印文件路径的默认行为也可以工作 标准输出:
{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1
简而言之:自定义文件描述符 3
用于临时交换标准输出(1
)和标准错误(2
),这样错误信息 独自的 可以通过管道传输到 grep
通过标准输出。
如果没有这些重定向,两个数据(文件路径) 和 错误消息将通过管道传输到 grep
通过标准输出,以及 grep
那么就无法区分 错误信息 Permission denied
和(假设的) 名称恰好包含的文件 词组 Permission denied
.
然而,与第一个解决方案一样,报告的退出代码将是 grep
的,不是 find
的,但可以应用与上面相同的修复。
对现有答案的注释:
有几点需要注意 迈克尔·布鲁克斯的回答,
find . ! -readable -prune -o -print
:这个需要 GNU
find
;值得注意的是,它不适用于 macOS。当然,如果您只需要使用 GNU 的命令find
, ,这对你来说不是问题。一些
Permission denied
错误可能 仍然 表面:find ! -readable -prune
报告此类错误 孩子 当前用户拥有的目录项r
许可,但缺乏x
(可执行)许可。原因是因为目录本身 是 可读,-prune
未执行,并且尝试下降 进入 然后该目录会触发错误消息。也就是说, 典型的 案例是针对r
允许失踪。笔记:以下几点是哲学和/或特定用例的问题,您可能会认为它与您无关,并且该命令很适合您的需求,特别是如果简单的话 印刷 路径就是你所做的一切:
- 如果 您将过滤拒绝权限的错误消息概念化 分离 您希望能够应用到的任务 任何
find
命令,然后是主动的相反方法 预防 权限被拒绝的错误需要将“噪音”引入find
命令,这也引入了复杂性和逻辑性 陷阱. - 例如,对迈克尔的回答(截至撰写本文时)得票最多的评论试图展示如何 延长 该命令包含一个
-name
过滤,如下:
find . ! -readable -prune -o -name '*.txt'
然而,这确实 不是 按预期工作,因为尾随-print
行动是 必需的 (可以在中找到解释 这个答案)。这种微妙之处可能会引入错误。
- 如果 您将过滤拒绝权限的错误消息概念化 分离 您希望能够应用到的任务 任何
第一个解决方案是 乔纳森·莱弗勒的回答,
find . 2>/dev/null > files_and_folders
, 正如他自己所说, 盲目沉默 全部 错误信息 (正如他也解释的那样,解决方法很麻烦并且不完全可靠)。 务实地说, ,然而,它是 最简单的解决方案, ,因为您可能会满足于假设任何和所有错误都与权限相关。雾的回答,
sudo find . > files_and_folders
, 简洁实用,但除了仅仅用于其他方面之外,其他任何事情都是不明智的 印刷 文件名, ,出于安全原因:因为你正在跑步 根 用户,“你的整个系统可能会被 find 中的错误或恶意版本弄乱,或者错误的调用会意外地写入一些内容,如果你使用正常权限运行它,则不会发生这种情况”(来自对 Mist 答案的评论经过 三重).中的第二个解决方案 维拉普托的回答,
find . 2>&1 | grep -v 'Permission denied' > some_file
存在误报的风险(由于通过管道发送标准输出和标准错误的混合),并且可能不报告 非- 通过 stderr 的权限拒绝错误,将它们与输出文件中的输出路径一起捕获。
其他提示
使用:
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
I/O 重定向 find
命令是: 2>&1 > files_and_folders |
。管道将标准输出重定向到 grep
命令并首先应用。这 2>&1
将标准错误发送到与标准输出相同的位置(管道)。这 > files_and_folders
将标准输出(但不是标准错误)发送到文件。最终结果是写入标准错误的消息被沿着管道发送,并且常规输出 find
被写入文件。这 grep
过滤标准输出(您可以决定您想要的选择性,并且可能需要根据区域设置和操作系统更改拼写)和最终结果 >&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
- 以避免“权限被拒绝”
- 并且不抑制(其他)错误消息
- AND 获取退出状态 0(“所有文件均已成功处理”)
适用于:查找(GNU findutils)4.4.2。背景:
- 这
-readable
测试匹配可读文件。这!
当测试为 false 时,运算符返回 true。和! -readable
匹配不可读的目录(&文件)。 - 这
-prune
操作不会下降到目录中。 ! -readable -prune
可以翻译为:如果目录不可读,请勿进入该目录。- 这
-readable
测试考虑了访问控制列表和其他权限工件-perm
测试忽略。
也可以看看 find
(1) 联机帮助页 了解更多详细信息。
如果您想从根“/”开始搜索,您可能会看到类似的输出:
find: /./proc/1731/fdinfo: Permission denied
find: /./proc/2032/task/2032/fd: Permission denied
这是因为许可。为了解决这个问题:
您可以使用 sudo 命令:
sudo find /. -name 'toBeSearched.file'
. 。它询问超级用户的密码,当输入密码时,您将看到您真正想要的结果。您可以使用将标准错误输出从(通常显示/屏幕)重定向到某个文件,并避免在屏幕上看到错误消息!重定向到特殊文件 /dev/null :
find /. -name 'toBeSearched.file' 2>/dev/null
您可以使用将标准错误输出从(通常显示/屏幕)重定向到标准输出(通常显示/屏幕),然后使用带 -v“invert”参数的 grep 命令进行管道传输,以不查看具有“权限被拒绝”的输出行词对:
find /. -name 'toBeSearched.file' 2>&1 | grep -v 'Permission denied'
我不得不使用:
find / -name expect 2>/dev/null
指定的什么,我想找到的名称,然后告诉它所有的错误重定向到/ dev / null的
期望是所述期望程序我正在寻找的位置。
管stderr
通过使用至/dev/null
的 2>的/ dev / null的强>
find . -name '...' 2>/dev/null
您还可以使用 -perm
和 -prune
谓词以避免下降到不可读的目录(另请参阅 如何从查找程序中删除“权限被拒绝”的打印输出语句?- Unix 和 Linux 堆栈交换):
find . -type d ! -perm -g+r,u+r,o+r -prune -o -print > files_and_folders
重定向标准误差。例如,如果您使用的是UNIX机器上的bash,你可以在标准错误重定向到/ dev / null的是这样的:
find . 2>/dev/null >files_and_folders
虽然上述方法不能解决 Mac OS X 的情况,因为 Mac Os X 不支持 -readable
switch 这是避免输出中出现“权限被拒绝”错误的方法。这可能会对某人有所帮助。
find / -type f -name "your_pattern" 2>/dev/null
.
如果您使用其他命令 find
, ,例如,查找目录中特定模式的文件的大小 2>/dev/null
仍然可以如下所示工作。
find . -type f -name "your_pattern" -exec du -ch {} + 2>/dev/null | grep total$
.
这将返回给定模式的文件的总大小。请注意 2>/dev/null
在 find 命令的末尾。
这些错误都打印到标准错误输出(FD 2)。要过滤出来,只要将所有的错误到/ dev / null的:
find . 2>/dev/null > some_file
或先加入stderr和stdout和然后用grep出这些特定错误:
find . 2>&1 | grep -v 'Permission denied' > some_file
简单回答:
find . > files_and_folders 2>&-
2>&-
关闭(-
) 标准错误文件描述符 (2
)因此所有错误消息都会被静音。
- 退出代码仍然是
1
如果有的话'Permission denied
' 否则会打印错误
GNU 的有力答案 find
:
find . -type d \! \( -readable -executable \) -prune -print -o -print > files_and_folders
将额外选项传递给 find
那 -prune
(防止下降)但仍然 -print
任何目录(-type
d
)不(\!
)两者都有 -readable
和 -executable
权限,或(-o
) -print
任何其他文件。
-readable
和-executable
选项是 GNU 扩展,而不是 POSIX标准- 可能还会回来'
Permission denied
' 在异常/损坏的文件上(例如,参见 错误报告 影响容器安装的文件系统使用lxcfs
< v2.0.5)
适用于任何 POSIX 兼容的可靠答案 find
(GNU、OSX/BSD 等)
{ LC_ALL=C find . 3>&2 2>&1 1>&3 > files_and_folders | grep -v 'Permission denied'; [ $? = 1 ]; } 3>&2 2>&1
用一个 管道 将标准错误流传递给 grep
, ,删除所有包含的行 'Permission denied'
细绳。
LC_ALL=C
设置 POSIX 语言环境 使用一个 环境变量, 3>&2 2>&1 1>&3
和 3>&2 2>&1
重复的文件描述符 将标准错误流传输到 grep
, , 和 [ $? = 1 ]
用途 []
反转返回的错误代码 grep
来近似原始行为 find
.
- 还将过滤任何
'Permission denied'
由于输出重定向而导致的错误(例如,如果files_and_folders
文件本身不可写)
要避免的只是的权限被拒绝的警告,告诉找到从搜索修剪他们忽略不可读文件。添加使用表达式作为或您的发现,如
find / \! -readable -prune -o -name '*.jbd' -ls
此大多说要(符合一个不可读文件并从列表中进行清理,)或(符合像 * .jbd 的名称,并用显示它〔 LS])。 (记住,默认情况下表达式AND'd除非你一起使用-or。)您需要在第二个表达-ls或者找到可以添加一个默认的动作以示无论是比赛,这也将显示所有的文件不可读
但是,如果你正在寻找您的系统上真正的文件,通常是没有理由看的/ dev,里面有很多很多的文件,所以你应该补充的是排除了一个表达式目录,如:
find / -mount \! -readable -prune -o -path /dev -prune -o -name '*.jbd' -ls
所以(匹配不可读文件,并从列表中修剪)或(匹配路径/ dev,并从列表中修剪)或(匹配文件等 * .jbd 并显示它)
使用
sudo find / -name file.txt
这是愚蠢的(因为你提升搜索)和不安全的,但更短的写了。
上述答案都不适合我。我在互联网上找到的所有内容都集中在:隐藏错误。没有一个能够正确处理进程返回代码/退出代码。我在 bash 脚本中使用 find 命令来定位某些目录,然后检查其内容。我使用退出代码评估命令 find 是否成功:值为零有效,否则失败。
这 上面提供了答案 经过 迈克尔·布鲁克斯 有时有效。但我有一种情况是失败的!我发现了这个问题并自己解决了。我需要在以下情况下修剪文件:
it is a directory AND has no read access AND/OR has no execute access
看到这里的关键问题是:和/或。我读到的一个很好的建议条件序列是:
-type d ! -readable ! -executable -prune
这并不总是有效。这意味着当匹配满足以下条件时会触发剪枝:
it is directory AND no read access AND no execute access
当授予读取访问权限但未授予执行访问权限时,此表达式序列将失败。
经过一些测试后,我意识到了这一点,并将我的 shell 脚本解决方案更改为:
很好找到/home*/ -maxdepth 5 -follow \
\( -类型 d -a !\(-可读-a-可执行\) \) -修剪 \
-o\
\(-type d -a -可读-a -可执行-a -name“${m_find_name}”\)-print
这里的关键是为组合表达式放置“not true”:
has read access AND has execute access
否则它没有完全访问权限,这意味着:修剪它。事实证明,在以前建议的解决方案失败的一种情况下,这对我有用。
我为评论部分中的问题提供了以下技术细节。如果细节过多,我深表歉意。
- ¿为什么使用命令nice?我明白了 这里. 。最初我认为在查看整个文件系统时降低进程优先级会很好。我意识到这对我来说没有意义,因为我的脚本仅限于几个目录。我将 -maxdepth 减少到 3。
- ¿为什么要在 /home*/ 内搜索?这与该线程无关。我通过使用非特权用户(非 root)编译源代码手动安装所有应用程序。它们安装在“/home”内。我可以让多个二进制文件和版本共存。我需要找到所有目录,以主从方式检查和备份。我可以有多个“/home”(在专用服务器内运行的多个磁盘)。
- 为什么使用-follow?用户可以创建到目录的符号链接。它的用处取决于,我需要记录找到的绝对路径。
可以使用grep -v反转匹配
-v, --invert-match select non-matching lines
是这样的:
find . > files_and_folders
cat files_and_folders | grep -v "permission denied" > files_and_folders
应魔术
= - 为MacOS = -
使用别名建立一个新的命令:只添加〜/ .bash_profile中一行:
alias search='find / -name $file 2>/dev/null'
和在新的终端窗口,你可以把它叫做:
$ file=<filename or mask>; search
例如:
$文件=等;搜索
如果使用的是CSH或TCSH,这里是一个解决方案:
( find . > files_and_folders ) >& /dev/null
如果要输出到终端:
( find . > /dev/tty ) >& /dev/null
您也简单的解决方案把你的查找结果在一个文件中。
找到。 -name 'NameOfSearchedFile' >> RESULTS.TXT