如何在 Kickstart 期间将 shell 脚本置于后台?

如何在 Kickstart 期间将 shell 脚本置于后台?

我有一个 Red Hat Kickstart 流程,它通过向状态服务器发出 POST 请求来报告关键点的进度。

%pre在和期间这很好%post,但是当它们之间发生实际构建时,这是一个信息黑洞。

我编写了一个简单的 shell 片段,用于报告已安装的软件包数量,以粗略了解进度。我已将以下内容放入%pre

%pre

## various other stuff here, all works fine ##

cat > /tmp/rpm_watcher.sh << EOF_RPM
PREV=-1
while true
do
    COUNT="\$(rpm -qa | wc -l)"
    if [ \${COUNT} -ne \${PREV} ] ; then
        /bin/wget --post-data " ${Hostname} : Package count \${COUNT}" ${builddest}/log
        PREV=\${COUNT}
    fi
    sleep 15
done
EOF_RPM
/bin/sh /tmp/rpm_watcher.sh &
disown -a
%end

但是,当我从上面将其作为后台任务启动时%pre,它会挂起等待脚本结束 -%pre永远不会完成(如果我终止生成的脚本%pre完成并且构建正确开始)。

我无法使用,因为它在预安装环境中不可用,使用和 也是nohup如此。at nowscreen

我尝试使用disown -a,它是可用的;这似乎成功地否认了该进程(这样它就属于 PID 1),但它仍然挂起等待脚本完成。

谁能给我提供替代方案吗?

答案1

你已经非常接近解决方案了。 Anaconda(安装程序)是用 Python 编写的,因此我深入研究了代码。

最终,它执行这样的脚本:

    rc = iutil.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)],
                                stdin = messages, stdout = messages, stderr = messages,
                                root = scriptRoot)

进一步挖掘,您可以找到“iutil.py”中定义的 iutil.execWithRedirect。该函数最终使用 subprocess.Popen (Python 内置)来执行命令。它还非常努力地从 %pre 脚本中获取 STDOUT 和 STDERR 的内容。

代码如下所示:

    #prepare tee proceses
    proc_std = tee(pstdout, stdout, program_log.info, command)
    proc_err = tee(perrout, stderr, program_log.error, command)

    #start monitoring the outputs
    proc_std.start()
    proc_err.start()

    proc = subprocess.Popen([command] + argv, stdin=stdin,
                            stdout=pstdin,
                            stderr=perrin,
                            preexec_fn=chroot, cwd=root,
                            env=env)

    proc.wait()
    ret = proc.returncode

    #close the input ends of pipes so we get EOF in the tee processes
    os.close(pstdin)
    os.close(perrin)

    #wait for the output to be written and destroy them
    proc_std.join()
    del proc_std

    proc_err.join()
    del proc_err

因此,利用您所拥有的,您可以通过分叉到后台来绕过 proc.wait() 和 os.close 调用。

proc_std和proc_err是重复调用的线程阅读线在 STDOUT 和 STDERR 上。他们继续读取直到遇到 EOF。由于您的脚本从 %pre 脚本继承了 STDOUT 和 STDERR 套接字,因此它们永远不会遇到 EOF。然后 Ananconda 挂起,等待读取 STDOUT 的线程退出(在“proc_std.join()”行上),但这从未发生。

这是一个非常令人困惑的问题,但最终是一个非常简单的解决方案。代替:

/bin/sh /tmp/rpm_watcher.sh &

使用

/bin/sh /tmp/rpm_watcher.sh > /dev/null 2>&1 < /dev/null &

这可确保您的脚本不会继承 STDOUT 和 STDERR,因此 Anaconda 不会挂起并且安装可以继续。

答案2

如果您将脚本中的 while 循环设置为背景,而不是让脚本背景化,如下所示:

while true
do
    COUNT="\$(rpm -qa | wc -l)"
    if [ \${COUNT} -ne \${PREV} ] ; then
        /bin/wget --post-data " ${Hostname} : Package count \${COUNT}" ${builddest}/log
        PREV=\${COUNT}
    fi
    sleep 15
done &

done请注意,我在循环行的末尾添加了“&”号while

参考

答案3

也许 Anaconda 的实现已经发展到打破了所提出的解决方案。我始终无法否认这个过程。

您现在可以在 Anaconda 环境中使用systemd,这对我有用(适应问题):

cat > /etc/systemd/system/rpm-watcher.service << EOF
[Service]
Type=simple
ExecStart=/bin/sh /tmp/rpm_watcher.sh
EOF

systemctl daemon-reload
systemctl start rpm-watcher

答案4

嗯,有时以“ at now”开头对我来说很合适

现在立即返回 - 并且启动的进程在后台运行......

atd当然必须运行:)

例如

/bin/echo "/custom/scripte/test.sh" | /usr/bin/at now

相关内容