如何从“查找”中排除所有“权限被拒绝”消息?

How can I exclude all "permission denied" messages from "find"?

提问人:Léo Léopold Hertz 준영 提问时间:4/18/2009 最后编辑:JahidLéo Léopold Hertz 준영 更新时间:3/16/2022 访问量:637648

问:

我需要隐藏所有被拒绝的邮件

find . > files_and_folders

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

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

如何同时隐藏错误?

bash 错误处理 :查找 文件权限

评论

0赞 HoldOffHunger 8/14/2021
好问题!不幸的是,前三个答案根本无法在 Debian Linux 上运行。或者至少我对它的配置。我需要法提赫的解决方案,.find /. -name 'toBeSearched.file' 2>/dev/null
0赞 Charlie Reitzel 3/16/2022
我发现最好使用该选项排除路径。它有助于否定避免打印修剪项的选项。/proc-path-prune

答:

644赞 Jonathan Leffler 4/18/2009 #1

用:

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 重定向为:。 管道将标准输出重定向到命令,并首先应用。将标准误差发送到与标准输出(管道)相同的位置。将标准输出(但不是标准错误)发送到文件。最终结果是,写入标准错误的消息被发送到管道中,而 的常规输出被写入文件。筛选标准输出(您可以决定它的选择性,并且可能必须根据区域设置和 O/S 更改拼写),最终意味着幸存的错误消息(写入标准输出)再次进入标准错误。最终重定向在终端上可以被视为可选的,但在脚本中使用它是一个非常好的主意,以便在标准错误上显示错误消息。find2>&1 > files_and_folders |grep2>&1> files_and_foldersfindgrep>&2

这个主题有无穷无尽的变化,这取决于你想做什么。这将适用于任何具有任何 Bourne shell 衍生物(Bash、Korn 等)和任何符合 POSIX 的 find 版本的 Unix 变体。

如果您希望适应系统上的特定版本,可能还有其他选项可用。特别是 GNU 有无数的选项,这是其他版本所没有的——参见当前公认的答案,了解其中一组选项。findfind

评论

11赞 Nik 10/25/2013
如果你像我一样,请注意缺乏空间是很重要的!,没有空间!2>/dev/null
25赞 Jonathan Leffler 10/26/2013
是一个没有任何空格的单元;它和文件名之间可以有一个空格。与其他重定向类似,例如(将标准误重定向到与标准输出相同的位置),或关闭标准误差等。有关剩余的血腥细节,请参阅重定向。(上面的代码是通用的类似 POSIX 的 shell,不是特定于 .)2>2>&12>&-bash
7赞 Gunchars 11/10/2014
这如何是一个可接受的解决方案?1) 您将所有错误重定向到 dev/null 2) 您正在过滤一个显式错误字符串!!取决于这些是出了名的脆弱,如果您的文件位于名为“权限被拒绝”的目录中怎么办?哎呀!
2赞 Jonathan Leffler 11/10/2014
@Gunchars:你提出的观点包含在答案中,或者明确的错误字符串包含在问题的规范中。第一个命令确实将所有错误发送到 ;第二个没有。答案提到了一个假设,即您没有任何名为 的文件。所以,我不清楚你真正反对的是什么。/dev/nullpermission denied
10赞 Gunchars 11/10/2014
我反对使用错误字符串来修改程序的输出。它大部分时间都有效,但简单不是正确的解决方案(在下面找到烫发)。举个例子,为什么这在OSX上不起作用,因为错误是“权限被拒绝”。对于任何其他系统也是如此,其中错误字符串甚至存在微小的差异(国际化有人吗?
23赞 Jason Coco 4/18/2009 #2

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

find . 2>/dev/null >files_and_folders
71赞 Matt 4/18/2009 #3

使用 2>/dev/null 通过管道传递stderr/dev/null

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

评论

3赞 shadowsheep 2/19/2018
即使在 Mac OSX 上,这对我来说也很好用。甚至find . -name '...' -print 2>/dev/null
13赞 viraptor 4/18/2009 #4

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

find . 2>/dev/null > some_file

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

find . 2>&1 | grep -v 'Permission denied' > some_file
107赞 Jeremy 2/4/2012 #5

我不得不使用:

find / -name expect 2>/dev/null

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

expect 是我正在搜索的 expect 程序的位置。

评论

3赞 Dhruv Kapoor 2/10/2014
@Masi,答案中的命令不使用 .相反,它只是此命令将尝试查找的文件的名称。expectexpect
2赞 Josip Rodin 9/24/2015
盲目地重定向所有 stderr 输出只是为了忽略一类错误消息通常是一个坏主意 - 您将在此过程中丢失所有其他任意错误。
123赞 Fatih Aksu 2/15/2012 #6

如果你想从根“/”开始搜索,你可能会看到这样的输出:

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'
    

评论

8赞 Stephen 7/16/2013
@scottmrogowski除了它没有回答这个问题......1. 要求系统管理员将您添加到 sudoers 文件中。2.sudo find...
4赞 DankMasterDan 6/21/2018
正是我想要的!
1赞 HoldOffHunger 8/14/2021
我已经有一段时间没有找到正确的答案了,在阅读了四个高票、长达一页的答案后,这些答案都是不正确的。谢谢!
31赞 sdaau 3/23/2014 #7

您还可以使用 and 谓词来避免下降到不可读的目录(另请参阅如何从查找程序中删除“权限被拒绝”打印语句? - Unix & Linux Stack Exchange):-perm-prune

find . -type d ! -perm -g+r,u+r,o+r -prune -o -print > files_and_folders

评论

5赞 mklement0 10/24/2016
-perm -g+r,u+r,o+r仅匹配为文件的所有 3 个安全主体设置了 (read) 权限的文件,这与当前用户是否可以读取该文件没有直接关系。它既有可能错过当前用户可以读取的文件,也有可能匹配他们无法读取的文件。r
0赞 Mattia72 11/29/2016
我认为会是一个很好的解决方案。find . -type d ! \( -perm -u+r -o -perm -g+r -o -perm -o+r \) -prune -o -print
2赞 mklement0 1/17/2017
@Mattia72:不,从根本上说,完全模拟是不可能的 - 请参阅我之前的评论并考虑这个示例:prints ,因为它的用户读取位是设置的,但它与用户有关,而不是当前用户。当前用户无法读取此文件;尝试。参见:我的这个答案-readable-permecho 'hi' > file; sudo chown nobody:nobody file; sudo chmod o-r file; find file -perm -u=rfilenobodycat file
310赞 Michael Brux 8/11/2014 #8

用:

find . ! -readable -prune -o -print

或更一般地说

find <paths> ! -readable -prune -o <other conditions like -name> -print
  • 以避免“权限被拒绝”
  • 并且不禁止显示(其他)错误消息
  • AND get exit status 0 (“所有文件都已成功处理”)

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

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

参见 find(1) 手册页以获取更多详细信息。

评论

6赞 Michael Brux 8/11/2014
已经提到了差异。如果你不明白,那么答案可能对你没有区别?STDOUT 是一样的 - STDERR 是不同的(你会得到这个答案的其他错误消息) - $?是不同的(当没有其他错误发生时,这个答案是 0 “成功” - 重定向到 dev/null 时总是> 0“不成功”) - 也许有人需要“正确”$?在脚本中
6赞 林果皞 4/11/2015
@Masi最明显的缺陷是 Jonathan 的答案 (grep -v) 将排除包含“拒绝权限”的文件名:)
67赞 tempestadept 4/30/2015
我觉得在这里补充一点是合适的,如果你需要添加一些其他的搜索条件,那应该用:-ofind . ! -readable -prune -o -name '*.txt'
26赞 Jonathan Leffler 6/28/2015
请注意,POSIX 不包括作为选项;BSD 和 Mac OS X 也没有(我不确定其他系统)。所以,在你有GNU保证的地方,这很好用,但如果你不能保证系统安装了GNU,那么如何适应它就不明显了。(它在 Linux 上可以正常工作;它可能在其他地方工作,也可能不工作。find-readablefindfindfind
7赞 con-f-use 1/16/2016
find . ! -readable -prune -o -name '*.txt'似乎无法使用 find 14.04 在 Ubuntu 4.2.2 上运行。它似乎使.出于某种奇怪的原因,我成功了-namefind . \( ! -readable -prune \) -o -name '*.txt' -print
4赞 simpleuser 9/16/2014 #9

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

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

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

但是,如果你在系统上查找真实文件,通常没有理由在 /dev 中查找,因为 /dev 有很多文件,所以你应该添加一个排除该目录的表达式,例如:

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

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

3赞 mist 12/16/2014 #10

sudo find / -name file.txt

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

评论

0赞 Léo Léopold Hertz 준영 12/16/2014
你在这里搜索整个文件系统,所以你的意思是“提升搜索”。为什么称它为不安全?因为它正在搜索整个文件系统?
2赞 mist 12/16/2014
因为 sudo 以 root 权限运行 find 命令,这基本上是一个坏主意。违反了隔离和最小特权原则。
4赞 tripleee 12/7/2015
这里的“提升”是特权,以 root 为根。您可能会因为错误或恶意版本而弄乱整个系统,或者错误地调用意外写入某些内容,如果您以正常权限运行它,则不会发生这种情况。sudofind
20赞 Bunti 2/2/2016 #11

虽然上述方法不能解决 Mac OS X 的情况,因为 Mac Os X 不支持开关,但这是避免输出中出现“权限被拒绝”错误的方法。这可能会对某人有所帮助。-readable

find / -type f -name "your_pattern" 2>/dev/null.

例如,如果您使用其他命令来查找目录中某些模式的文件的大小,则仍然可以如下所示。find2>/dev/null

find . -type f -name "your_pattern" -exec du -ch {} + 2>/dev/null | grep total$.

这将返回给定模式的文件的总大小。请注意 find 命令末尾的 。2>/dev/null

评论

0赞 Léo Léopold Hertz 준영 2/2/2016
与OS X的良好绑定!乔纳森的回答解释了这部分。你能解释一下这部分吗?2>/dev/null-exec du -ch {} + 2>/dev/null | grep total$
1赞 Bunti 2/3/2016
@Masi 您可以使用任何带有选项的命令对命令找到的文件或目录执行进一步操作。 计算匹配的每个文件的大小,该输出的最后一行是与 匹配的所有文件的总和。请参见手册页。 只是过滤提取总计的行(这是最后一行)。-execfinddu -ch file_patternfile_patternfile_patterndugrep total
325赞 mklement0 10/31/2016 #12

注意:

  • 这个答案可能比用例所保证的更深入,并且在许多情况下发现 2>/dev/null 可能足够好。对于跨平台视角和对一些高级 shell 技术的讨论,它可能仍然很有意义,以找到尽可能强大的解决方案,即使所防范的情况可能在很大程度上是假设的。

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

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

注意:

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

  • >(...)是一个(很少使用的)输出进程替换,它允许将输出(在本例中为 stderr 输出 () 重定向到内部命令的 stdin。
    除了 和 之外,原则上也支持它们,但尝试将它们与来自 stderr 的重定向相结合,就像这里所做的那样 (),似乎被默默地忽略了 (in )。
    2>>(...)bashzshksh2> >(...)ksh 93u+

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

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

这种方法是:

  • 可靠:仅适用于错误消息(而不是文件路径和错误消息的组合,可能导致误报),并且将权限被拒绝的错误消息以外的错误消息传递到 stderr。grep

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


符合POSIX标准的解决方案:

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

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

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

请注意,重定向的顺序很重要:必须排在第一位2>&1

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

唯一的缺点是整个退出代码将是 grep 命令的,而不是 的,在这种情况下,这意味着:如果根本没有错误或只有权限拒绝错误,则退出代码将是(信号失败),否则(权限拒绝以外的错误) - 这与意图相反。
也就是说,find 的退出代码很少被使用,因为它通常除了基本故障(例如传递不存在的路径)之外几乎没有传达任何信息。
但是,由于缺乏权限而无法访问某些输入路径的特定情况反映在 的退出代码中(在 GNU 和 BSD 中):如果处理的任何文件发生权限拒绝错误,则退出代码设置为 。
find10findfind1

以下变体解决了以下问题:

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

现在,退出代码指示是否发生了除此以外的任何错误:如果是,则否则。
换言之:退出代码现在反映了命令的真实意图:如果根本没有错误或发生权限拒绝错误,则报告成功 ()。
可以说,这比仅仅传递 的退出代码要好,就像在顶部的解决方案中一样。
Permission denied100find


注释中的gniourf_gniourf建议使用复杂的重定向对此解决方案进行(仍然符合 POSIX 标准)的泛化,即使将文件路径打印到 stdout 的默认行为也适用于

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

简而言之:自定义文件描述符用于临时交换 stdout () 和 stderr (),以便可以通过 stdout 单独传递错误消息。312grep

如果没有这些重定向,数据(文件路径)错误消息都将通过 stdout 通过管道传输,然后无法区分错误消息名称恰好包含短语 的(假设)文件。grepgrepPermission deniedPermission denied

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


关于现有答案的说明:

  • 关于迈克尔·布鲁克斯的回答,有几点需要注意:find . ! -readable -prune -o -print

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

    • 某些错误可能仍会浮出水面:报告当前用户具有权限但缺少(可执行)权限的目录的子项的此类错误。原因是由于目录本身可读的,因此不会执行,并且尝试下降到该目录会触发错误消息。也就是说,典型的情况是缺少许可。Permission deniedfind ! -readable -prunerx-pruner

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

      • 如果将拒绝权限的错误消息的筛选概念化为一个单独的任务,并且希望能够应用于任何命令,则主动防止拒绝权限错误的相反方法需要在命令中引入“噪音”,这也会带来复杂性和逻辑陷阱findfind
      • 例如,对 Michael 的回答(截至撰写本文时)获得最多票的评论试图展示如何通过包含过滤器来扩展命令,如下所示:

        然而,这并不能按预期工作,因为尾随操作是必需的(可以在此答案中找到解释)。这种微妙之处可能会引入错误。
        -namefind . ! -readable -prune -o -name '*.txt'-print
  • 正如他自己所说,Jonathan Leffler 回答中的第一个解决方案是盲目地静音所有错误消息(正如他所解释的那样,解决方法很麻烦且不完全健壮)。然而,从实用的角度来看,这是最简单的解决方案,因为您可能满足于假设任何和所有错误都与权限相关。find . 2>/dev/null > files_and_folders

  • Mist 的回答简洁而务实,但出于安全原因,除了打印文件名之外,其他任何事情都是不明智的:因为你是以 root 用户身份运行的,“你可能会因为 find 中的错误或恶意版本而弄乱整个系统,或者一个不正确的调用,它意外地写入了一些东西,如果你以正常权限运行它,这不会发生”(来自 Tripleee 对 Mist 回答的评论)。sudo find . > files_and_folders

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

评论

5赞 gniourf_gniourf 12/26/2016
只是一个简单的问题:为什么你使用过程替代而不仅仅是管道:?find . 2>&1 > files_and_folders | grep -v 'Permission denied' >&2
3赞 gniourf_gniourf 12/26/2016
@LéoLéopoldHertz준영: 如果您不想输出到外部文件,只需执行更多管道:{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1
3赞 gniourf_gniourf 12/26/2016
@LéoLéopoldHertz준영:只是它符合 POSIX 标准。进程替换是特定于 Bash 的。>(...)
3赞 gniourf_gniourf 12/26/2016
我不确定是否应该强调和宣传退出代码的保留:的退出代码是出了名的无用。在这里,它很可能是非零的(而且是无用的)。findfind
3赞 wjordan 12/30/2016
POSIX 显式需要文件模式权限才能“搜索”目录(检索所包含文件的 inode)。 执行此操作是为了进入子目录(除了需要列出目录中的文件的权限之外)。这不是“错误”或“移植错误”。execute/searchfindread
3赞 Jordi Ferran 12/22/2016 #13

以上答案都不适合我。无论我在互联网上找到什么,都集中在:隐藏错误。没有正确处理进程返回代码/退出代码。我在 bash 脚本中使用命令 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 ! \( -可读 -a -可执行 \) \) -prune \ -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?用户可能会创建指向目录的符号链接。它的用处取决于,我需要记录找到的绝对路径。

评论

0赞 Léo Léopold Hertz 준영 12/22/2016
感谢您的回答和很好的观察!我在这里打开了赏金,以便更好地预览您的答案。我认为这是一个很好的发现,不会阻止读取和执行访问。- - 您能解释一下您为什么使用 and 吗?nicefind $HOME -maxdepth 5 -follow ...
2赞 wjordan 12/25/2016
如上所述,shell 脚本不是通用的(仅列出匹配的目录),并且包含几个与问题 (, , , ) 无关的选项。我添加了一个答案,该答案更简洁地解决了“过滤可读但不可执行目录”的具体问题,同时保持通用性。${m_find_name}nice/home*-maxdepth 5-follow
13赞 wjordan 12/25/2016 #14

简单的答案:

find . > files_and_folders 2>&-

2>&- 关闭 (-) 标准错误文件描述符 (2),以便所有错误消息静音。

  • 如果打印任何“”错误,退出代码仍将是1Permission denied

GNU的鲁棒性答案:find

find . -type d \! \( -readable -executable \) -prune -print -o -print > files_and_folders

传递额外的选项以查找 -prune(防止下降到)但仍然 -print 任何没有 \!) 和 -executable 权限的目录 (-typed),或 (-o-print 任何其他文件。

  • -readable-executable 选项是 GNU 扩展,不是 POSIX 标准的一部分
  • 在异常/损坏的文件上仍可能返回“”(例如,请参阅使用 < v2.0.5 影响容器挂载文件系统的错误报告Permission deniedlxcfs

适用于任何 POSIX 兼容(GNU、OSX/BSD 等)的可靠答案find

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

使用管道将标准错误流传递给 grep,删除包含“权限被拒绝”字符串的所有行。

LC_ALL=C 使用环境变量 3>&2 2>&1 1>&3 和 3>&2 2>&1 重复文件描述符设置 POSIX 语言环境,将标准错误流管道传递给 grep,[ $? = 1 ] 使用 [] 反转 grep 返回的错误代码,以近似 find 的原始行为。

  • 还将过滤由于输出重定向而导致的任何错误(例如,如果文件本身不可写)'Permission denied'files_and_folders

评论

0赞 Léo Léopold Hertz 준영 12/25/2016
您如何看待 JordiFerran 的答案建议?- - 你能比较一下你的答案吗?
2赞 wjordan 12/25/2016
如上所述,该答案的 shell 脚本不是通用的(仅列出与 ${m_find_name} 匹配的目录),并且包含几个与问题无关的选项(nice、/home*、-maxdepth 5、-follow)。这个答案更简洁地解决了“过滤可读但不可执行目录”的具体问题,同时保持通用性。
1赞 mklement0 12/26/2016
@wjordan:谢谢。我已经删除了我的评论,但有一点仍然适用:基于 -的解决方案不值得展示,因为它比引文所暗示的更根本地做了一些与预期不同的事情:它是一个纯粹以文件为中心的测试,文件的所有者和组有关,两者都与调用命令的用户没有任何保证的关系(请参阅此答案我的。看起来您修改后的 GNU 解决方案现在无法捕获源自文件的权限被拒绝错误。-perm
0赞 mklement0 12/26/2016
我不认识您正在使用的语法(既不是 GNU 也不是 BSD),但让我用一个独立的例子来说明我的观点: prints ,因为它的用户读取位是设置的,但它与用户有关,而不是当前用户。当前用户无法读取此文件;尝试。echo 'hi' > file; sudo chown nobody:nobody file; sudo chmod o-r file; find file -perm -u=rfilenobodycat file
1赞 wjordan 12/26/2016
@mklement0感谢您的讨论,我设法产生了您在另一个测试中描述的行为(不知道我第一次做错了什么),这似乎不适用于确定用户的当前权限。从此答案中删除了该替代项。-perm
2赞 Leonardo Hermoso 12/27/2016 #15

你可以使用 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

应该到魔法

2赞 Jan aka uptech 8/10/2017 #16

-=对于 MacOS=-

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

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

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

$ file=<filename or mask>; search

例如:

$ 文件=etc;搜索

2赞 Kayle Sawyer 1/17/2018 #17

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

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

如果要输出到终端:

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

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

评论

0赞 yadav 5/11/2020
我想 grep 所有 txt 文件并排除隐藏文件/目录,省略要打印的“权限被拒绝”消息。我正在使用 csh shell。我使用了以下命令,但它们不起作用,找到.-键入 f -iname “.txt” -not -path '*/\.' |egrep -v “权限被拒绝” 找到 .-键入 f -iname “.txt” -not -path '*/\.'2>/dev/null 低于错误。find:路径必须在表达式之前:2 用法:find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...][表达式]
3赞 user1735921 6/25/2021 #18

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

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

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

-3赞 Orun 7/9/2021 #19

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

find . -name foo -readable

1赞 leogama 9/23/2021 #20

针对 GNU 的优化解决方案find

至少对于某些系统+文件系统组合,不需要文件来获取其类型。然后,您可以在测试可读性之前检查它是否是一个目录,以加快搜索速度‡ - 我在所做的测试中改进了大约 30%。因此,对于长时间搜索或运行频率足够高的搜索,请使用以下方法之一:findstat

打印所有可见内容

$ 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

笔记

and(逗号)运算符是 GNU 扩展。此表达式-readable,

$ find . [expression] , [expression]

在逻辑上等价

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

这是因为在所讨论的用例中,启用此优化的实现将完全避免使用非目录文件。findstat


编辑:shell函数

这是我最终得到的一个 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 中的输出错误......运行时间似乎是等效的。

0赞 Charlie Reitzel 3/16/2022 #21

为了在整个文件系统中搜索某些文件,例如,除了导致各种错误的树之外,我使用以下方法:hosts/proc

# find / -path /proc ! -prune -o -name hosts -type f
/etc/hosts

注意:由于 is 始终为 true,因此必须否定它以避免在输出中看到该行。我尝试了使用方法,发现它在 /proc 下返回当前用户可以读取的各种内容。因此,“OR”条件不会达到您的期望/想要。-prune/proc! -readable

我从 find 手册页给出的示例开始,请参阅选项。-prune