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

Léo*_* 준영 778 error-handling bash file-permissions find

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

find . > files_and_folders
Run Code Online (Sandbox Code Playgroud)

我正在尝试这样的消息出现.我需要收集所有不会出现的文件夹和文件.

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

如何同时隐藏错误?

Jon*_*ler 537

使用:

find . 2>/dev/null > files_and_folders
Run Code Online (Sandbox Code Playgroud)

Permission denied当然,这不仅隐藏错误,还隐藏所有错误消息.

如果你真的想要保留其他可能的错误,例如符号链接上的跳数太多,而不是允许拒绝的错误,那么你可能不得不猜测你没有很多名为"权限被拒绝"的文件并尝试:

find . 2>&1 | grep -v 'Permission denied' > files_and_folders
Run Code Online (Sandbox Code Playgroud)

如果您只想过滤标准错误,可以使用更精细的构造:

find . 2>&1 > files_and_folders | grep -v 'Permission denied' >&2
Run Code Online (Sandbox Code Playgroud)

find命令的I/O重定向是:2>&1 > files_and_folders |.管道将标准输出重定向到grep命令并首先应用.的2>&1发送标准误差相同的地方标准输出(管).的> files_and_folders发送标准输出(但不是标准误差)到一个文件.最终结果是写入标准错误的消息沿管道发送,并将常规输出find写入文件.该grep过滤器的标准输出(你可以决定你要如何选择它是,并且可能根据地区不同和O/S改变拼写)和最终>&2意味着幸存的错误消息(写到标准输出)到标准错误再一次.最终的重定向在终端上可以被视为可选的,但在脚本中使用它是一个非常好的主意,以便在标准错误中出现错误消息.

这个主题有无穷无尽的变化,取决于你想做什么.这将适用于任何带有任何Bourne shell衍生产品(Bash,Korn,...)和任何符合POSIX标准版本的Unix版本find.

如果您希望适应系统上的特定版本find,可能还有其他选择.GNU find尤其具有其他版本中无法提供的无数选项 - 请参阅当前接受的一个选项集的答案.

  • `2>`是一个没有任何空格的单位; 你可以在它和文件名之间留一个空格.与其他重定向类似,例如`2>&1`(将标准错误重定向到与标准输出相同的位置),或'2>& - `关闭标准错误等.请参阅[重定向](http:/ /www.gnu.org/software/bash/manual/bash.html#Redirections)了解其余的血腥细节.(上面的代码是类似于POSIX的通用shell,不是特定于`bash`.) (19认同)
  • 我反对grepping错误字符串来修改程序的输出.它大部分时间都可以工作,但是简单的不是正确的解决方案(找到下面的烫发).为了举例说明原因,这不适用于OSX,因为错误是"权限被拒绝".对于错误字符串中甚至存在微小差异的任何其他系统也是如此(国际化任何人?) (10认同)
  • 如果你像我一样,请注意缺乏空间很重要!`2>/dev/null`,没有空格! (9认同)
  • 这怎么可以接受?1)您将所有错误重定向到dev/null 2)您正在过滤显式错误字符串!! 根据这些是着名的脆弱,如果您的文件位于名为"权限被拒绝"的目录中该怎么办?哎呀! (4认同)
  • 我不得不使用大写P,因为这是我的终端输出的内容:find.2>&1 | grep -v'权限被拒绝' (3认同)
  • @Gunchars:您提出的要点包含在答案中-或明确的错误字符串包含在问题的说明中。第一个命令确实将所有错误发送到`/ dev / null`;第二个没有。答案提到了这样的假设,即您没有任何名为“权限被拒绝”的文件。因此,我不清楚您真正反对的是什么。 (2认同)

Mic*_*rux 278

使用:

find . ! -readable -prune -o -print
Run Code Online (Sandbox Code Playgroud)

或更一般地说

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

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

  • -readable测试与可读文件匹配.!当测试为假时,运算符返回true.并且! -readable匹配不可读的目录(和文件).
  • -prune操作不会进入目录.
  • ! -readable -prune 可以翻译为:如果目录不可读,请不要进入.
  • -readable测试考虑了访问控制列表和-perm测试忽略的其他权限假象.

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

  • 我觉得在这里添加一个如果你需要添加一些其他搜索条件是合适的,那应该用`-o`:`find来完成.!-readable -prune -o -name'*.txt'` (64认同)
  • 请注意,POSIX`find`不包含`-readable`作为选项; 既不是BSD的'find`,也不是Mac OS X(我不确定其他系统).所以,在你保证GNU`find`的地方,这很好用,但如果你不能保证系统安装了GNU`find`,那么如何调整它并不明显.(它在Linux上运行良好;它可能在其他地方运行,也可能不运行.) (21认同)
  • 已经提到了差异.如果你不明白,那么答案可能对你没什么影响?STDOUT是相同的 - STDERR是不同的(你得到这个答案的其他错误消息) - $?是不同的(这个答案为0"成功",当没有其他错误发生时 - 重定向到dev/null时总是> 0"不成功" - 也许有人需要"正确"$?在脚本中 (6认同)
  • @Masi最明显的缺陷是Jonathan的回答(grep -v)将排除包含'权限被拒绝'的文件名:) (6认同)
  • `找到.!-readable -prune -o -name'*.txt'`似乎不能使用find 4.2.2在Ubuntu 14.04上运行.好像是````.出于某种奇怪的原因,我在"找到"方面取得了成功.\(!-readable -prune \)-o -name'*.txt'-print` (6认同)
  • 我认为这是线程更优雅的解决方案.我喜欢成功的结果$? (5认同)
  • @con-f-use 您的命令有效,因为您在末尾添加了 `-print`。作用于`-name '*.txt' 的匹配。当你将`-print` 添加到`-o`(逻辑或)中的一个子句时,find 知道你只想打印那部分。否则,如果默认打印它找到的所有内容。不可读的东西被“发现”了,虽然不可读。(...正如 DreadPirateShawn 发布的链接中所描述的那样,现在我注意到了) (3认同)
  • @ con-f-use - 我有同样的问题,我发现我只需要`-print`,而不是复杂的括号. (2认同)
  • @con-f-use 请参阅此处的附加说明:括号和 `-print`:http://stackoverflow.com/questions/1489277/how-to-use-prune-option-of-find-in-sh (2认同)

mkl*_*nt0 250

注意:
*这个答案可能比用例保证更深入,并且find 2>/dev/null在许多情况下可能已经足够好了.对于跨平台的观点以及为了找到尽可能强大的解决方案而讨论一些先进的shell技术可能仍然有意义,即使防范的案例可能在很大程度上是假设的.
*如果您的系统配置为显示本地化的错误消息,请在find下面的调用前加上LC_ALL=C(LC_ALL=C find ...)以确保报告英语消息,以便grep -v 'Permission denied'按预期工作.但是,任何显示的错误消息将以英语显示.

如果您的shell是bash或者zsh,那么只需使用符合POSIX标准的功能,即使是相当简单的解决方案也是健壮的.虽然它本身不是POSIX的一部分,但大多数现代Unix平台都附带它,使这个解决方案具有广泛的可移植性:findbash

find . > files_and_folders 2> >(grep -v 'Permission denied' >&2)
Run Code Online (Sandbox Code Playgroud)

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

  • >(...)是一个(很少使用)输出 进程替换,允许将输出重定向(在本例中,stderr output(2>)到命令的stdin内>(...).
    除了bashzsh,原则上ksh支持它们,但试图将它们与重定向结合起来stderr,就像在这里完成的那样(),似乎被默默地忽略(in ).2> >(...)ksh 93u+

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

这种方法是:

  • robust:grep仅应用于错误消息(而不是文件路径和错误消息的组合,可能导致误报),并且除了权限拒绝之外的错误消息将传递给stderr.

  • 无副作用:find的退出代码被保留:无法访问文件系统项目中的至少一个遇到的退出码结果1(虽然这不会告诉你的错误是否其他比许可被拒绝的人发生了(太)).


符合POSIX标准的解决方案:

完全符合POSIX标准的解决方案有限制或需要额外的工作.

如果find的输出是在被捕获文件反正(或完全抑制),然后从基于管线的解决方案乔纳森·莱弗勒的回答很简单,健壮,符合POSIX标准:

find . 2>&1 >files_and_folders | grep -v 'Permission denied' >&2
Run Code Online (Sandbox Code Playgroud)

请注意,重定向的顺序很重要: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 ]; }
Run Code Online (Sandbox Code Playgroud)

现在,退出代码指示任何错误,是否比其他 Permission denied发生:1如果是这样,0否则.
换句话说:退出代码现在反映了命令的真实意图:0如果没有错误或发生权限拒绝错误,则报告success().
这可以说比传递find退出代码更好,就像在顶部的解决方案一样.


评论中的gniourf_gniourf提出了一种(仍然符合POSIX标准)使用复杂重定向来推广此解决方案,即使将文件路径打印到stdout的默认行为也是如此:

{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1
Run Code Online (Sandbox Code Playgroud)

简而言之:自定义文件描述符3用于临时交换stdout(1)和stderr(2),因此单独的错误消息可以grep通过stdout 传送到.

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

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


关于现有答案的说明:

  • 有几点需要注意迈克尔Brux的回答,find . ! -readable -prune -o -print:

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

    • 某些Permission denied错误可能仍然存在:find ! -readable -prune报告当前用户具有权限但缺少(可执行)权限的目录的子项目的此类错误.原因是因为目录本身可读的,不会被执行,并且尝试下降该目录然后会触发错误消息.也就是说,典型的情况是许可被遗漏.rx-pruner

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

      • 如果您将权限被拒绝错误消息的过滤概念化为您希望能够应用于任何命令的单独任务,那么主动防止权限被拒绝错误的相反方法需要在命令中引入"噪声" ,这也引入了复杂性和逻辑陷阱. findfind
      • 例如,对迈克尔答案的最高投票评论(截至本文撰写时)试图通过包含过滤器来展示如何扩展命令-name,如下所示:
        find . ! -readable -prune -o -name '*.txt'
        但是,这不能按预期工作,因为需要执行尾随-print操作(可在此答案中找到解释).这种微妙之处可能会引入漏洞.
  • 在第一个解决方案乔纳森·莱弗勒的回答,find . 2>/dev/null > files_and_folders如他自己陈述, 一味沉默所有的错误信息(和解决方法很麻烦并没有完全健壮,他也解释了).从务实角度来说,但是,这是最简单的解决方案,因为你可能会内容承担任何和所有的错误都会被允许相关.

  • 雾的回答,sudo find . > files_and_folders,简洁,务实的,但不明智的不仅仅是任何其他打印的文件名,出于安全方面的原因:是因为你作为运行用户,"你可能有你的整个系统在发现bug被搞砸了或者是一个恶意版本,或者是一个意外写入错误的错误调用,如果你以正常的权限运行它,就不会发生这种情况"(来自对三人的薄雾回答的评论).

  • 在第二个解决方案viraptor的答案,find . 2>&1 | grep -v 'Permission denied' > some_file运行误报的风险(由于通过管道传送输出和错误的混合),以及潜在的,而不是报告通过stderr -permission被拒绝的错误,捕捉他们旁边的输出路径在输出文件中.

  • 只是一个简单的问题:为什么你使用流程替换而不仅仅是管道:`find.2>&1> files_and_folders | grep -v'Permission denied'>&2`? (4认同)
  • POSIX显式需要`execute/search`文件模式权限才能'搜索'目录(检索包含文件的inode).`find`这样做是为了进入一个子目录(除了要求`read`权限列出目录中的文件).这不是'错误'或'移植错误'. (3认同)
  • @LéoLéopoldHertz준영:如果你不想输出到外部文件,只需做更多的管道:`{find.3>&2 2>&1 1>&3 | grep -v'权限被拒绝'>&3; } 3>&2 2>&1` (2认同)
  • @LéoLéopoldHertz준영:只是它符合POSIX标准.进程替换`>(...)`是特定于Bash的. (2认同)
  • 我不确定应该强调和宣传`find`的退出代码的保存:`find`的退出代码是众所周知的无用的.在这里,它很可能会非零(并且无用). (2认同)

Fat*_*ksu 108

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

find: /./proc/1731/fdinfo: Permission denied
find: /./proc/2032/task/2032/fd: Permission denied
Run Code Online (Sandbox Code Playgroud)

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

  1. 你可以使用sudo命令:sudo find /. -name 'toBeSearched.file'.它询问超级用户的密码,输入密码后你会看到你真正想要的结果.

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

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

    find /. -name 'toBeSearched.file' 2>&1 | grep -v 'Permission denied'
    
    Run Code Online (Sandbox Code Playgroud)

  • @scottmrogowski除了它没有回答问题... 1.请求系统管理员将你添加到sudoers文件.2."sudo find ..." (7认同)
  • 正是我要找的! (2认同)

小智 91

我不得不使用:

find / -name expect 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

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

期待成为我正在寻找的期待计划的位置.

  • @Masi,答案中的命令不使用`expect`.相反,`expect`只是该命令试图找到的文件的名称. (3认同)
  • 盲目地重定向所有stderr输出以仅仅忽略一类错误消息通常是一个坏主意-您将在此过程中丢失所有其他任意错误。 (2认同)

Mat*_*att 58

stderr/dev/null通过使用2>的/ dev/null的

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

  • 即使在 Mac OSX 上,这对我来说也很好用。甚至`找到。-name '...' -print 2&gt;/dev/null` (2认同)

sda*_*aau 30

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

find . -type d ! -perm -g+r,u+r,o+r -prune -o -print > files_and_folders
Run Code Online (Sandbox Code Playgroud)

  • `-perm -g + r,u + r,o + r`仅匹配对所有3个_file's_安全主体具有`r`(读取)权限集的文件,这与_current是否有直接关系user_可以读取该文件.它有可能错过当前用户_can_读取的文件并匹配他们无法读取的文件. (4认同)
  • @ Mattia72:不,从根本上讲,不可能完全用-perm来模仿-readable-请参阅我之前的评论并考虑以下示例:'echo'hi'&gt; file; sudo chown nobody:nobody file; sudo chmod或文件;find file -perm -u = r`打印`file`,因为它的用户读位已设置,但它与`nobody`用户有关,而不与当前用户有关。当前用户无法读取此文件;试试`cat文件`。另请参阅:我的[this answer](http://stackoverflow.com/questions/4458120/unix-find-search-for-executable-files/29039160#29039160)。 (2认同)

Jas*_*oco 23

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

find . 2>/dev/null >files_and_folders
Run Code Online (Sandbox Code Playgroud)


Bun*_*nti 19

虽然上述方法没有解决Mac OS X的情况,因为Mac OS X不支持-readable切换,但这是如何避免输出中的"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命令的末尾.


vir*_*tor 13

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

find . 2>/dev/null > some_file
Run Code Online (Sandbox Code Playgroud)

或者首先加入stderr和stdout然后grep out那些特定的错误:

find . 2>&1 | grep -v 'Permission denied' > some_file
Run Code Online (Sandbox Code Playgroud)


wjo*_*dan 10

简单回答:

find . > files_and_folders 2>&-

2>&-closing(-)标准错误文件描述符(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>&3并使用3>&2 2>&1 重复的文件描述符将标准错误流传递给grep,并[ $? = 1 ]使用它[]来反转返回的错误代码grep以近似原始行为find.

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

  • 所述答案的shell脚本不是通用的(仅列出与$ {m_find_name}匹配的目录),并包含几个与问题无关的选项(nice,/ home*, - maxdepth 5,-follow).这个答案更简洁地解决了"过滤可读但不可执行的目录"的具体问题,同时保留了一般用途. (2认同)