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

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

find . > files_and_folders

我正在试验何时出现此类消息。我需要收集所有未出现的文件夹和文件。

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

如何同时隐藏错误?

592312 次浏览

用途:

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尤其具有其他版本中不可用的无数选项-请参阅当前接受的答案以了解一组此类选项。

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

find . 2>/dev/null >files_and_folders

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

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

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

find . 2>/dev/null > some_file

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

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

我不得不使用:

find / -name expect 2>/dev/null

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

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

如果你想从root开始搜索 "/" , 你可能会看到输出如下:

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

是因为权限的原因。要解决此问题:

  1. 您可以使用sudo命令:

    sudo find /. -name 'toBeSearched.file'

It asks super user's password, when enter the password you will see result what you really want. If you don't have permission to use sudo command which means you don't have super user's password, first ask system admin to add you to the sudoers file.

  1. You can use redirect the Standard Error Output from (Generally Display/Screen) to some file and avoid seeing the error messages on the screen! redirect to a special file /dev/null :

    find /. -name 'toBeSearched.file' 2>/dev/null
  2. You can use redirect the Standard Error Output from (Generally Display/Screen) to Standard output (Generally Display/Screen), then pipe with grep command with -v "invert" parameter to not to see the output lines which has 'Permission denied' word pairs:

    find /. -name 'toBeSearched.file' 2>&1 | grep -v 'Permission denied'

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

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

用途:

find . ! -readable -prune -o -print

或更一般

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

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

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

另见#0(1)manpage了解更多细节。

要避免只是权限拒绝警告,请告诉查找通过从搜索中修剪它们来忽略不可读的文件。将表达式作为OR添加到您的查找中,例如

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

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

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

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

所以(匹配不可读的文件并从列表中删除)(匹配路径 /dev并从列表中删除)(匹配文件如*. jbd并展示它)

使用

sudo find / -name file.txt

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

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

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

备注:

  • 这个答案可能比用例权证更深入,#0在许多情况下可能足够好。它可能仍然对跨平台视角感兴趣,并对一些高级shell技术的讨论感兴趣,以找到尽可能健壮的解决方案,即使所防范的案例可能在很大程度上是假设的。

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

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

备注:

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

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

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

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

这种方法是:

  • 强大grep仅应用于错误信息(而不是文件路径和错误消息的组合,可能导致误报),并且权限拒绝之外的错误消息会传递给stderr。

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


符合POSIX的解决方案:

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

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

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

注意重定向的顺序很重要:2>&1必须是第一

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

唯一的缺点是整体退出代码将是#0命令的,而不是find,在这种情况下意味着:如果有错误或只有权限拒绝错误,退出代码将是1(信号故障),否则(权限拒绝错误以外的错误)0-这与意图相反。也就是说,#0的退出代码无论如何都很少使用,因为它经常传递基本失败之外的很少信息,例如传递不存在的路径。
然而,甚至只有一些的输入路径由于缺乏权限而无法访问find的退出代码(在GNU和BSDfind中):如果处理的文件任何发生权限拒绝错误,退出代码设置为1

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

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

现在,退出代码指示是否发生任何错误除了Permission denied1如果是,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,而不是find,但可以应用与上述相同的修复。


关于现有答案的注释:

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

    • 它需要GNUfind;值得注意的是,它不能在macOS上工作。当然,如果您只需要命令来使用GNUfind,这对您来说不是问题。

    • 一些Permission denied错误可能会仍然出现:find ! -readable -prune报告了当前用户具有r权限但缺乏x(可执行)权限的目录儿童项的此类错误。原因是因为目录本身可读,-prune未被执行,并且尝试下降该目录然后触发错误消息。也就是说,find ! -readable -prune0的情况是r权限丢失。

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

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

  • 雾的回答sudo find . > files_and_folders是简洁和实用的,但不建议任何其他只是打印文件名,出于安全原因:因为你是作为root用户运行的,“你有可能让你的整个系统被查找或恶意版本中的bug搞砸,或者错误的调用意外地写入了一些东西,如果你以正常权限运行这个就不会发生这种情况”(来自tripleee对雾的回答的评论)。

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

上述答案对我都不起作用。无论我在Internet上找到什么,都专注于:隐藏错误。没有正确处理返回代码/退出代码的过程。我在bash脚本中使用命令查找来定位一些目录,然后检查它们的内容。我使用退出代码评估命令查找成功:值为零有效,否则失败。

上面提供的答案 by迈克尔·布鲁克斯有时会起作用。但我有一种情况会失败!我发现了问题并自己修复了它。我需要在以下情况下修剪文件:

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

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

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

好的找到 /home*/-max深度5-跟随\
\(-type d-a!\(-可读-a-可执行\)\)-prune\
-o\
\(-type d-a-可读-a-可执行-a-名称"${m_find_name}" \) -print

这里的关键是为组合表达式放置“not true”:

has read access AND has execute access

否则它没有完全访问权限,这意味着:修剪它。这在以前建议的解决方案失败的一个场景中证明对我有效。

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

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

简单的回答:

find . > files_and_folders 2>&-

2>&-关闭(-)标准错误文件描述符(2),因此所有错误消息都保持沉默。

  • 退出代码仍将是1如果任何'Permission denied'错误将被打印

GNUfind的强大答案:

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 ]使用[]反转错误代码返回的grep近似的原始行为find.

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

您可以使用grep-v反转匹配

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

像这样:

find . > files_and_folderscat 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

例如:

$file=etc;搜索

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

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

如果你想输出到终端:

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

然而,正如“csh-whynot”FAQ所描述的,您不应该使用CSH。

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

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

让我们不要做不必要的工程,你只是想搜索你的文件,对吗?那么这是一个命令,它将为你列出文件,如果它们存在于你可以访问的区域。

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

find . -name foo -readable

针对GNUfind的优化解决方案

至少对于一些系统+文件系统的组合,find不需要stat一个文件来获取它的类型。然后你可以在测试易读性以加快搜索之前检查它是否是一个目录-我做的测试提高了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

备注

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

$ find . [expression] , [expression]

逻辑等效

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

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


编辑:shell函数

这是我最终使用的一个POSIX shell函数,用于将此测试附加到任何表达式。它似乎可以很好地使用隐式-print和命令行选项:

findr () {j=$#; done=while [ $j -gt 0 ]; doj=$(($j - 1))arg="$1"; shifttest "$done" || case "$arg" in-[A-Z]*) ;;  # skip options-*|\(|!)     # find start of expressionset -- "$@" \( -type d ! -readable -prune -o -true \)done=true;;esacset -- "$@" "$arg"donefind "$@"}

答案中列出的另外两个选项导致POSIX shell中的语法错误(甚至无法获取包含函数定义的文件)或ZSH中的错误输出……运行时间似乎是等效的。

要在整个文件系统中搜索某些文件,例如hosts,除了/proc树,它会导致各种错误,我使用以下命令:

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

注意:因为-prune总是正确,所以你必须对其进行否定以避免在输出中看到/proc行。我尝试了使用! -readable的方法,发现它在当前用户可以读取的 /proc下返回各种内容。所以“OR”条件并没有做你期望/想要的事情。

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