如何从 shell 脚本输出中抑制 stdout / stderr?

如何从 shell 脚本输出中抑制 stdout / stderr?

我有一个脚本应该停止并恢复在后台运行的进程:

process_id=`ps -eaf | grep -i daemon | grep -v grep | grep -v status | grep -v stop | awk '{print $2}'`
(kill -STOP $process_id) &
... # do something else 
(kill -CONT $process_id) &

这工作正常,但随后在 STDOUT / STDERR 中出现:

[1]  +  8545 Suspended (signal)            /etc/init.d/...

到目前为止我尝试:

(kill -STOP $process_id)

(kill -STOP $process_id) & > /dev/null

/etc/init.d/{name_of_the_daemon} start > /dev/null

(kill -STOP $process_id & ) 2>/dev/null 

(kill -STOP $process_id & disown;) 2>/dev/null 

set +m
(kill -STOP $process_id) & 

(kill -STOP $process_id) & 1>&2

这些是我正在执行的步骤:

  1. 创建一个文件 fff 在/etc/init.d/
  2. 粘贴下面的脚本
  3. chmod 755 fff
  4. /etc/init.d/fff 启动

之后,我收到“暂停”消息......

根据@sourcejedi,我的脚本不是守护进程;当脚本的子进程被挂起时,会出现“挂起”消息

我怎样才能抑制 shell 中仅输出的那条特定消息?

这是我的脚本的一个非常简单的版本:

#!/bin/bash

pid_script=`ps -eaf | grep -i fff | grep -v grep | grep -v status | grep -v stop | awk '{print $2}'`

case "$1" in
    start)
    ( sleep 3; kill -STOP $pid_script ) &
    sleep 10;
    (sleep 1; kill -CONT $pid_script) &
    ;;
    stop)
    for p in $pid_script # kill all the other processes related with this script (if any)
        do
            kill -9 $p
        done
esac

答案1

当您看到 时[1] + 7766 Suspended (signal) ...,这是 shell 打印的一条消息,告诉您它的一个子进程已被挂起。

fff示例中,需要考虑两个 shell 进程。您的初始交互式 shell 以及作为子进程运行的 shell 脚本。

您的脚本安排自行挂起。交互式 shell 打印“挂起”消息。所以这不是一个可以打开或关闭的选项在脚本里面

此外,您无法在交互式 shell 中设置选项来打开或关闭此特定消息。不可能单独“抑制”此消息......基本上是因为这永远不是您想要做的:-)。

我认为fff脚本无论如何都无法成功恢复自身。我认为可以对其进行修改以实现此目的。然而,恢复本身是一个糟糕的主意。当您暂停脚本时,交互式 shell 会再次显示其命令提示符。即,如果您没有看到“暂停”消息,则看起来您的脚本已完成。但无论哪种方式,如果您的脚本设法自行恢复,它都会尝试从用户那里夺回对终端的控制权,无论他们同时开始做什么。不是很好!


我认为您需要了解,例如,如果您从终端启动了一个进程,并且它是一个交互式 shell 的子进程,那么它绝对不是一个守护进程过程。

开始一个守护进程从您的终端,程序必须在启动期间自行 fork() 。原来的进程应该退出,这允许继续运行的进程重新养育例如(在传统的 unix 中)PID 1 又名进程init。它还必须包括更多步骤才能从终端分离。参见此处的示例:在 shell 中守护进程?

此外,如果您的系统使用systemd,您需要了解/etc/init.d/需要使用旧脚本来启动systemctl start。 Debian 和其他地方的打包init.d脚本包含一个兼容性 hack,可以为您完成此操作。但你应该不是使用该功能。这是造成混乱的秘诀。你写的脚本没有这个功能,所以你必须使用systemctl start fff

我强烈建议不要尝试将脚本中的游戏fffsystemctl start.

实际上systemctl使用不同的方法来启动后台服务进程。它向PID 1(init进程)发送消息systemd,PID 1启动所请求的程序。如果您定义了本机 systemd 服务,则程序不需要自行守护进程。如果您使用旧init.d脚本,程序仍然需要对自身进行守护进程,但它实现的唯一作用是告诉systemd脚本init.d已完成启动。 (这使得可以注意到守护进程中的一些启动失败,但不幸的是,许多现有程序在守护进程步骤之后可能会发生启动失败)。

您不想担心脚本是否以及如何systemdinit.d脚本自行停止和恢复做出反应。

答案2

不确定我是否正确理解你的目标,但这对我来说是这样的:

  1. 启动“守护进程”,实际上只是持续运行的进程:top -d1 >out

  2. tail -f out如果您愿意,可以在第二个航站楼

  3. 在我运行的第三个终端中kill -STOP $(ps -eFH | grep "top -d" |grep -v grep|awk '{print $2}'

您将在启动守护程序的第一个终端中看到“挂起”消息,但在文件中out不会有此类消息。

相关内容