在zsh中
rm foo.bar印刷rm: foo.bar: No such file or directory。rm foo.bar 2>/dev/null正如我所料,什么也没打印。但如果命令包含模式匹配,则错误不会被抑制2>/dev/null:
rm *.bar印刷zsh: no matches found: *.bar。rm *.bar 2>/dev/null打印相同。zsh 中是否有抑制错误消息的通用方法?针对各种错误消息的一种简单方法。
Kam*_*ski 11
当您尝试运行rm *.bar但没有匹配的文件时*.bar,基本上会发生两种情况:
POSIX 行为是 shellrm以文字*.bar作为参数运行。该工具尝试删除一个字面名称为 的文件*.bar(就像您运行rm \'*.bar\'),它失败并打印类似rm: *.bar: No such file or directory. 这就是 POSIX shell 的方式(sh ) 和兼容 shell 的行为方式。
非 POSIX 行为是 shell 检测到不存在匹配项,打印类似的内容并且根本no matches found: *.bar不运行。这就是 Zsh 默认的行为方式。(作为比较:在 Bash 中,您可以通过以下方式切换到此行为rm shopt -s failglob。)
(前一种情况)的错误rm被打印到 stderrrm。来自 shell 的错误(后一种情况)被打印到 shell 的 stderr 中。
中的重定向仅影响+rm *.bar 2>/dev/null的 stderr 。在你的例子中甚至没有运行。rmrm
要重定向主 shell 的 stderr,您需要exec. 我所说的“主 shell”是指您键入内容的交互式 shell;或者,如果运行脚本,则 shell 解释该脚本。例子:
exec 2>/dev/null\nRun Code Online (Sandbox Code Playgroud)\n在 Zsh 中你甚至可以关闭它:
\nexec 2>&-\nRun Code Online (Sandbox Code Playgroud)\n一个合理的方法是预先复制原始的 stderr,以防万一您以后需要使用(或恢复)它。示例(请注意,如果您想将此代码粘贴到交互式 Zsh 中,那么您应该setopt interactive_comments首先调用):
exec 2>/dev/null\nRun Code Online (Sandbox Code Playgroud)\n这7是一个任意的单位数字,否则不用作文件描述符。前两行可以写为一行:exec 7>&2 2>/dev/null ; 同样,最后两行也可以。
注意rm,任何在没有 stderr 重定向的情况下调用的命令(如whatever)都会从 shell 继承 stderr。这意味着在上面的示例中rm(如果它曾经运行过)并将whatever其错误消息(如果有)打印到/dev/null. 当您可以调用任何数字或命令后exec 2>/dev/null,它们都会有/dev/null其 stderr。如果您确实想抑制各种错误消息,那么这就是方法。
该解决方案适用于许多 shell,而不仅仅是 Zsh。如果您想重定向交互式 shell 的 stderr,请记住一些不太复杂的 shell 使用 stderr 来打印其提示符。
\n请注意,进程可能会重定向其自己的 stderr(就像我们的 shell 所做的那样exec 2>\xe2\x80\xa6);或者它可以将错误消息打印到标准输出或/dev/tty(它不应该,但技术上可以)。因此exec 2>/dev/null不您不会看到类似错误消息的消息。
之后exec 2>/dev/null您仍然可以根据需要重定向任何命令的 stderr。例如如果相反whatever我们有:
whatever 2>&7\nRun Code Online (Sandbox Code Playgroud)\n那么它的错误消息将转到我们故意保存为文件描述符的原始 stderr7。
exec不是重定向 shell 的 stderr(或其他文件描述符)的唯一方法。rm您可以像对待一样对待一个外壳(尽管不是整个主外壳)rm \xe2\x80\xa6 2>/dev/null. 您可以像这样处理子 shell:
( rm *.bar ) 2>/dev/null\nRun Code Online (Sandbox Code Playgroud)\n或者只是主 shell 解释的一些代码:
\n{ rm *.bar; } 2>/dev/null\nRun Code Online (Sandbox Code Playgroud)\n(;这里在 Zsh 中是可选的,在其他一些 shell 中是强制的;我只是希望代码也能在 Zsh 之外工作)。
这些行中的任何一行都可以解决您的问题。在抑制来自 shell 的错误消息的上下文中,这两行是等效的++。
\n请注意,重定向从(/开始并以/{结束,其范围是有限的。您仍然可以将许多命令放在括号内,因此“有限”范围实际上可能是整个脚本。或者它可能只是脚本的一部分(包括本答案前面介绍的,无论你想要什么)。事实上,重定向在/之后停止工作,使得这种方法成为保存和恢复 stderr 的巧妙替代方案)}whatever)}exec。
+严格来说:它会影响“ rm”在成为(或试图成为)之前和之后rm。耐心听我说。中的重定向rm \xe2\x80\xa6 2>/dev/null开始时是由分叉 shell 执行的重定向,该 shell 即将用rm可执行文件替换自身。该 shell 在尝试将自身替换为 .stderr 之前会重定向其自己的 stderr rm。执行重定向后报告的任何错误都将转到/dev/null. 例如,如果rm找不到,则已执行的重定向将抑制该command not found错误。
++从技术上讲( \xe2\x80\xa6 )创建了一个子shell,{ \xe2\x80\xa6 }但实际上并没有。子 shell 的行为就像一个单独的 shell 进程,它继承变量和当前工作目录,但不能更改其父 shell 中的任何内容(例如变量或当前工作目录)。它可能会也可能不会被实现为一个真正独立的过程,重要的是行为。OTOH{ \xe2\x80\xa6 }仅出于某种目的对命令进行分组(在我们的例子中,目的是重定向)。这并不意味着当您使用{ \xe2\x80\xa6 };时永远不会有子 shell 例如,在管道中,除最后一个之外的所有部分无论如何都是子外壳(在某些外壳中:包括最后一个在内的所有部分)。这些技术细节与我们的问题本身无关,但总的来说它们可以产生影响。
| 归档时间: |
|
| 查看次数: |
5326 次 |
| 最近记录: |