【问题标题】:Is there a way to make bash job control quiet?有没有办法让 bash 作业控制安静下来?
【发布时间】:2012-06-19 09:03:35
【问题描述】:

在后台运行作业时,Bash 非常冗长:

$ echo toto&
toto
[1] 15922
[1]+  Done                    echo toto

由于我正在尝试并行运行作业并使用输出,因此我想找到一种使 bash 静音的方法。有没有办法去掉这个多余的输出?

【问题讨论】:

  • 当我的 dotfile 有一些我不想在每次启动新的 shell 会话时看到的文件清理逻辑时,这尤其令人讨厌!

标签: bash shell unix parallel-processing


【解决方案1】:

您可以使用括号在子shell 中运行后台命令,这将使作业控制消息静音。例如:

(sleep 10 & )

【讨论】:

  • 这就是我最终做的事情(请参阅接受答案的 cmets)。
  • 出色而简单。谢谢
  • @mklement0 虽然您的建议在技术上是正确的,但它并不能回答问题。构造 { command & } 2>/dev/null 隐藏了初始作业控制消息,但无法在睡眠完成时抑制“[1]-Done”消息。
  • @Dave:感谢您让我深入挖掘。让我换个方式总结一下:(sleep 10 &) 方便地使创建和终止消息都静音,但您会失去对后台作业的控制。为避免这种情况,请使用 { sleep 10 & } 2>/dev/null 使 creation 消息静音,并类似地使用 waitkill 使 termination 消息静音(可能并不总是一个选项)。或者,set +m 可用于绝对地使终止消息静音,但是,这具有许多潜在的不良副作用。我的回答(希望)有完整的故事。
  • () 表示法产生一个子shell,然后分叉另一个&,这不是最佳的
【解决方案2】:

注意:以下内容适用于交互式 Bash 会话。在脚本中,作业控制消息从不打印出来。

2 个基本场景用于使 Bash 的作业控制消息静音


一劳永逸:

CodeGnome's helpful answer answer 建议 将后台命令包含在一个简单的子 shell 中 - 例如,(sleep 10 &) - 这有效地使工作控制消息静音 - 无论是在工作 creation 还是在工作终止

这有一个重要的副作用

  • 通过使用控制运算符& 子shell中,您失去对后台作业的控制 - jobs 不会列出它,并且%%(最近启动的作业的规范(ID))和$!(最近启动的(作为其一部分)进程的PID)都不会反映它。[ 1]

对于一劳永逸的场景,这不是问题

  • 您只需启动后台作业,
  • 然后您让它自行完成(并且您相信它可以正常运行)。

[1] 可以想象,您可以自己寻找进程,通过搜索正在运行的进程以找到与其命令行匹配的进程,但这很麻烦,而且不容易变得健壮。


稍后启动和控制:

如果您想继续控制工作,以便以后可以:

  • 杀了它,如果需要的话。
  • 同步等待(稍后)完成,

需要一种不同的方法:

  • 以下处理创建作业控制消息的静音,但为了终止作业控制消息分类 ,您必须关闭作业控制 shell 选项

    • set +mset -m 重新开启)
    • 警告:这是一个全局设置,具有许多重要的副作用,特别是:
      • 后台命令的标准输入是 /dev/null 而不是当前 shell 的。
      • 用于暂停 (Ctrl-Z) 和延迟暂停 (Ctrl-Y) 前台命令的键盘快捷键已禁用。
      • 有关全文,请参阅 man bash 并(不区分大小写)搜索出现的“作业控制”。
  • 使创建作业控制消息静音,请将后台命令包含在组命令中,并将后者的stderr输出重定向到@987654332 @

    { sleep 5 & } 2>/dev/null
    

以下示例展示了如何在原则上保持对作业的控制的同时安静地启动后台作业。

$ set +m; { sleep 5 & } 2>/dev/null # turn job-control option off and launch quietly
$ jobs # shows the job just launched; it will complete quietly due to set +m 

如果您想要关闭作业控制选项 (set +m),唯一的方法就是让终止作业控制消息静音是 kill 工作或 wait 工作:

警告:有 两种极端情况这种技术仍然会产生输出:

  • 如果后台命令立即尝试从标准输入读取
  • 如果后台命令立即终止

安静地启动工作(如上,但没有set +m):

$ { sleep 5 & } 2>/dev/null

悄悄给wait

$ wait %% 2>/dev/null    # use of %% is optional here

悄悄给kill它:

{ kill %% && wait; } 2>/dev/null

额外的wait 是使 Bash 通常异步显示的终止作业控制消息(在实际进程终止时,杀死后不久)成为 所必需的wait 的同步输出,然后允许静音。

但是,如上所述,如果作业自行完成,仍会显示作业控制消息。

【讨论】:

  • 请注意,组命令技术还有一个额外的警告:命令本身的标准错误输出被抑制。
【解决方案3】:

将其包装在一个虚拟脚本中:

quiet.sh:

#!/bin/bash
$@ &

然后调用它,将你的命令作为参数传递给它:

./quiet.sh echo toto

根据您的输入,您可能需要使用引号。

【讨论】:

  • 聪明,但似乎不适用于某些 bash 结构。示例: quiet.sh "[ -e quiet.sh ] || echo prout"
  • "$@" 应该绝对被引用。这在大多数情况下都不起作用 - 仅用于执行单个简单命令。您也可以使用bash -c 'cmds',或bash -s <<"EOF"
  • 更好的是,使用 () 在子shell中运行:(echo toto&)
  • 这样你就失去了工作控制权。分叉的进程成为 init 的子进程。如果你真的想管理并行的东西,运行一个单独的脚本不会有这个问题,但听起来这对你来说实际上并不重要。
  • @static_rtti,“更糟糕”并不是描述它的正确方式。未引用的$@ 的行为与未引用的$* 相同,但存在相同的错误。你不想要那些错误。
【解决方案4】:

交互式,不。它将始终显示作业状态。您可以使用set -b 影响状态何时显示。

没有什么可以阻止您使用命令的输出(通过管道或存储变量等)。作业状态由 shell 发送到控制终端,不与其他 I/O 混合。如果你正在做一些复杂的工作,解决方案是编写一个单独的脚本。

只有当你的 bashrc 中有函数使用你想要直接访问交互环境的作业控制时,作业消息才是真正的问题。不幸的是,您对此无能为力。

【讨论】:

    【解决方案5】:

    一种解决方案(无论如何在 bash 中)是将所有输出路由到 /dev/null

        echo 'hello world' > /dev/null &
    

    除了 bg 进程的 id 之外,上述内容不会为您提供任何输出。

    【讨论】:

    • 这只会抑制命令的输出本身——“bg 进程的 id”正是 OP 想要静音的作业控制消息。
    猜你喜欢
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 2011-10-13
    • 1970-01-01
    相关资源
    最近更新 更多