867

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

find . > files_and_folders

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

是否可以将权限级别定向到files_and_folders文件?

如何同时隐藏错误?

4

20 回答 20

578

采用:

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系统上的特定版本,可能会有其他选项可用。特别是GNUfind具有其他版本中不可用的无数选项 - 请参阅当前接受的一组选项的答案。

于 2009-04-17T21:57:42.587 回答
303

笔记:

  • 这个答案可能比用例保证的更深入,并且find 2>/dev/null在许多情况下可能已经足够好了。对于跨平台的观点和讨论一些先进的 shell 技术以找到尽可能健壮的解决方案可能仍然很有趣,即使所防范的情况可能在很大程度上是假设性的。

如果您的shell 是bashzsh,那么有一个解决方案既健壮又相当简单只使用符合 POSIX 的find特性;虽然bash它本身不是 POSIX 的一部分,但大多数现代 Unix 平台都附带了它,这使得该解决方案具有广泛的可移植性:

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

笔记:

  • 如果您的系统配置为显示本地化错误消息,请在find下面的调用前加上LC_ALL=C ( LC_ALL=C find ...) 以确保报告英文消息,以便grep -v 'Permission denied'按预期工作。但是,任何确实显示的错误消息都将始终以英文显示。

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

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

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

这种方法是:

  • 健壮grep仅适用于错误消息(而不适用于文件路径和错误消息的组合,可能导致误报),并且除了权限被拒绝的错误消息之外的错误消息被传递到标准错误。

  • side-effect free :find的退出代码被保留:无法访问遇到的至少一个文件系统项目会导致退出代码1(尽管这不会告诉您是否发生了除了权限被拒绝的错误之外的错误(也))


符合 POSIX 标准的解决方案:

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

如果无论如何要在文件find中捕获 ' 的输出(或完全抑制),那么Jonathan Leffler 的答案中基于管道的解决方案是简单、健壮且符合 POSIX 的:

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

请注意,重定向的顺序很重要:2>&1must come first

预先在文件中捕获标准输出输出允许通过管道2>&1发送错误消息,然后可以明确地对其进行操作。grep

唯一的缺点是整个退出代码将是grep命令的,而不是find,这在这种情况下意味着:如果根本没有错误或只有权限被拒绝的错误,则退出代码将是1(signaling failure ),否则 (许可被拒绝以外的错误)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

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

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


现有答案的注释:

  • 关于Michael Brux 的回答,有几点需要注意find . ! -readable -prune -o -print

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

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

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

      • 如果您将权限拒绝错误消息的过滤概念化为您希望能够应用于任何命令的单独任务,那么主动防止权限拒绝错误的相反方法需要在命令中引入“噪音” ,这也引入了复杂性和逻辑缺陷 findfind
      • 例如,对 Michael 的回答(截至撰写本文时)投票最多的评论试图展示如何通过包含过滤器来扩展-name命令,如下所示:
        find . ! -readable -prune -o -name '*.txt'
        但是,这不能按预期工作,因为需要-print尾随操作(可以在这个答案中找到解释)。这种微妙之处可能会引入错误。
  • 正如他自己所说, Jonathan Leffler 的回答中的第一个解决方案会盲目地使所有错误消息静音(而且解决方法很麻烦,而且并不完全可靠,正如他所解释的那样)。然而,务实地说,这是最简单的解决方案,因为您可能满足于假设任何和所有错误都与权限相关。find . 2>/dev/null > files_and_folders

  • 薄雾的答案,简洁实用sudo find . > files_and_folders,但出于安全原因,除了打印文件名之外,其他任何事情都是不明智的:因为你以root用户身份运行,“你有可能让你的整个系统被 find 中的错误搞砸或恶意版本,或意外写入某些内容的错误调用,如果您以正常权限运行此操作,则不会发生这种情况”(来自Tripleee对雾的回答的评论)。

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

于 2016-10-31T03:51:28.573 回答
299

采用:

find . ! -readable -prune -o -print

或更一般地说

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

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

  • 测试-readable匹配可读文件。当!测试为假时,运算符返回真。并! -readable匹配不可读的目录(&files)。
  • -prune操作不会下降到目录中。
  • ! -readable -prune可以翻译为:如果目录不可读,请不要深入其中。
  • -readable测试考虑了访问控制列表和-perm测试忽略的其他权限伪影。

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

于 2014-08-11T00:44:07.097 回答
119

如果您想从根目录 "/" 开始搜索,您可能会看到如下输出:

find: /./proc/1731/fdinfo: Permission denied
find: /./proc/2032/task/2032/fd: Permission denied

是因为许可。要解决这个问题:

  1. 您可以使用 sudo 命令:

    sudo find /. -name 'toBeSearched.file'
    

它询问超级用户的密码,当输入密码时,你会看到你真正想要的结果。如果您没有使用 sudo 命令的权限,这意味着您没有超级用户的密码,请先让系统管理员将您添加到 sudoers 文件中。

  1. 您可以使用将标准错误输出从(通常显示/屏幕)重定向到某个文件,并避免在屏幕上看到错误消息!重定向到特殊文件 /dev/null :

    find /. -name 'toBeSearched.file' 2>/dev/null
    
  2. 您可以使用将标准错误输出从(通常显示/屏幕)重定向到标准输出(通常显示/屏幕),然后使用带有 -v "invert" 参数的 grep 命令进行管道传输,以查看具有“权限被拒绝”的输出行词对:

    find /. -name 'toBeSearched.file' 2>&1 | grep -v 'Permission denied'
    
于 2012-02-15T08:27:40.037 回答
102

我不得不使用:

find / -name expect 2>/dev/null

指定我想要查找的名称,然后告诉它将所有错误重定向到 /dev/null

期望是我正在寻找的期望程序的位置。

于 2012-02-04T02:29:45.227 回答
66

使用2>/dev/null进行管道stderr传输/dev/null

find . -name '...' 2>/dev/null

于 2009-04-17T21:59:16.357 回答
30

您还可以使用-permand-prune谓词来避免进入不可读的目录(另请参阅如何从 find 程序中删除“permission denied”打印输出语句?- Unix & Linux Stack Exchange):

find . -type d ! -perm -g+r,u+r,o+r -prune -o -print > files_and_folders
于 2014-03-23T15:08:56.193 回答
23

重定向标准错误。例如,如果您在 unix 机器上使用 bash,您可以将标准错误重定向到 /dev/null,如下所示:

find . 2>/dev/null >files_and_folders
于 2009-04-17T21:57:44.567 回答
20

虽然上述方法不能解决 Mac OS X 的情况,因为 Mac OS X 不支持-readableswitch,但这是您可以避免输出中出现“Permission denied”错误的方法。这可能会帮助某人。

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/nullfind 命令末尾的。

于 2016-02-01T22:57:56.910 回答
13

这些错误被打印到标准错误输出 (fd 2)。要过滤掉它们,只需将所有错误重定向到 /dev/null:

find . 2>/dev/null > some_file

或者先加入 stderr 和 stdout,然后用 grep 找出那些特定的错误:

find . 2>&1 | grep -v 'Permission denied' > some_file
于 2009-04-17T22:00:10.897 回答
12

简单的回答:

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任何目录()不具有()和权限,或()任何其他文件。-typed\!-readable-executable-o-print

适用于任何 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>&33>&2 2>&1 grep[ $? = 1 ][]grepfind

  • 还将过滤'Permission denied'由于输出重定向引起的任何错误(例如,如果files_and_folders文件本身不可写)
于 2016-12-25T04:17:05.630 回答
4

为了避免仅仅出现权限被拒绝警告,请通过从搜索中删除它们来告诉 find 忽略不可读的文件。将表达式作为 OR 添加到您的查找中,例如

find / \! -readable -prune -o -name '*.jbd' -ls

这主要是说(匹配一个不可读的文件并从列表中删除它)(匹配一个像*.j​​bd这样的名称并显示它 [with ls])。(请记住,默认情况下,除非您使用 -or,否则表达式是 AND 一起使用的。)您需要在第二个表达式中使用 -ls,否则 find 可能会添加一个默认操作来显示任一匹配项,这也会显示所有不可读的文件.

但是如果你在你的系统上寻找真实的文件,通常没有理由去寻找 /dev,它有很多很多的文件,所以你应该添加一个不包括那个目录的表达式,比如:

find / -mount \! -readable -prune  -o  -path /dev -prune  -o  -name '*.jbd' -ls

所以(匹配不可读的文件并从列表中修剪)(匹配路径 /dev 并从列表中修剪)(匹配*.jbd之类的文件并显示它)

于 2014-09-16T00:59:49.617 回答
3

采用

sudo find / -name file.txt

这很愚蠢(因为你提升了搜索)并且不安全,但写起来要短得多。

于 2014-12-16T11:37:48.253 回答
2

以上答案都不适合我。我在 Internet 上找到的所有内容都集中在:隐藏错误。None 正确处理进程返回代码/退出代码。我在 bash 脚本中使用命令 find 来定位一些目录,然后检查它们的内容。我使用退出代码评估命令 find 是否成功:零值有效,否则失败。

Michael Brux上面提供的答案有时有效。但我有一个失败的场景!我发现了问题并自己解决了。我需要在以下情况下修剪文件:

it is a directory AND has no read access AND/OR has no execute access

看到这里的关键问题是:AND/OR。我读到的一个很好的建议条件序列是:

-type d ! -readable ! -executable -prune

这并不总是有效。这意味着当匹配时触发修剪:

it is directory AND no read access AND no execute access

当授予读取访问权限但没有执行访问权限时,此表达式序列将失败。

经过一些测试后,我意识到这一点并将我的 shell 脚本解决方案更改为:

不错的发现 /home*/ -maxdepth 5 -follow \
    \( -type d -a ! \( -readable -a -executable \) \) -prune \
    -o \
    \( -type d -a -readable -a -可执行文件 -a -name "${m_find_name}" \) -print

这里的关键是为组合表达式放置“不正确”:

has read access AND has execute access

否则它没有完全访问权限,这意味着:修剪它。事实证明,在以前建议的解决方案失败的一种情况下,这对我有用。

我在评论部分提供了以下问题的技术细节。如果细节过多,我深表歉意。

  • ¿ 为什么使用命令 nice?我明白。最初我认为在查看整个文件系统时降低进程优先级会很好。我意识到这对我来说毫无意义,因为我的脚本仅限于几个目录。我将 -maxdepth 减少到 3。
  • ¿ 为什么要在 /home*/ 中搜索?这与该线程无关。我通过非特权用户(不是root)编译的源代码手动安装所有应用程序。它们安装在“/home”中。我可以有多个二进制文件和版本一起生活。我需要以主从方式定位所有目录、检查和备份。我可以拥有多个“/home”(在专用服务器中运行的多个磁盘)。
  • ¿ 为什么使用 -follow?用户可能会创建指向目录的符号链接。它的用处取决于,我需要记录找到的绝对路径。
于 2016-12-22T11:06:40.663 回答
2

您可以使用 grep -v invert-match

-v, --invert-match        select non-matching lines

像这样:

find . > files_and_folders
cat files_and_folders | grep -v "permission denied" > files_and_folders

应该到魔法

于 2016-12-27T04:02:43.893 回答
2

-=对于 MacOS=-

使用别名创建一个新命令:只需添加 ~/.bash_profile 行:

alias search='find / -name $file 2>/dev/null'

在新的终端窗口中,您可以调用它:

$ file=<filename or mask>; search

例如:

$文件=等;搜索

于 2017-08-09T23:10:28.153 回答
2

如果您使用的是 CSH 或 TCSH,这里有一个解决方案:

( find . > files_and_folders ) >& /dev/null

如果要输出到终端:

( find . > /dev/tty ) >& /dev/null

但是,正如“csh-whynot”常见问题解答所述,您不应该使用 CSH。

于 2018-01-16T18:13:23.267 回答
2

只需使用它来搜索系统中的文件。

find / -name YOUR_SEARCH_TERM 2>&1 | grep YOUR_SEARCH_TERM

让我们不要做不必要的过度工程,您只想搜索您的文件对吗?如果文件存在于您可以访问的区域中,那么该命令将为您列出文件。

于 2021-06-25T10:15:48.960 回答
1

GNU find†的优化解决方案</sup>

至少对于某些系统+文件系统组合,find不需要stat文件来获取其类型。然后,您可以在测试可读性之前检查它是否是一个目录,以加快搜索速度‡</sup> — 我所做的测试有 30% 的改进。因此,对于长时间搜索或经常运行的搜索,请使用以下之一:

打印所有可见的东西

$ find . -print -type d ! -readable -prune
$ find . -type d ! -readable -prune , [expression] -print

打印可见文件

$ find . -type d \( ! -readable -prune -o -true \) -o [expression] -print

打印可见目录

$ find . -type d -print ! -readable -prune
$ find . -type d \( ! -readable -prune , [expression] -print \)

仅打印可读目录

$ find . -type d ! -readable -prune -o [expression] -print

笔记

†</sup>-readable,(逗号)运算符是 GNU 扩展。这个表达

$ find . [expression] , [expression]

逻辑上等价于

$ find . \( [expression] -o -true \) [expression]

‡</sup> 这是因为find启用此优化的实现将stat在讨论的用例中完全避免使用非目录文件。


编辑:外壳函数

这是我最终使用的 POSIX shell 函数,用于将此测试添加到任何表达式。-print使用隐式和命令行选项似乎可以正常工作:

findr () {
    j=$#; done=
    while [ $j -gt 0 ]; do
        j=$(($j - 1))
        arg="$1"; shift
        test "$done" || case "$arg" in
            -[A-Z]*) ;;  # skip options
            -*|\(|!)     # find start of expression
                set -- "$@" \( -type d ! -readable -prune -o -true \)
                done=true
                ;;
        esac
        set -- "$@" "$arg"
    done
    find "$@"
}

答案中列出的其他两个替代方案导致 POSIX shell 中的语法错误(甚至无法获取包含函数定义的文件)或 ZSH 中的错误输出......运行时间似乎是相同的。

于 2021-09-22T19:50:27.463 回答
-2

最小的解决方案就是添加readable标志。

find . -name foo -readable

于 2021-07-08T23:26:25.133 回答