通常您不会与脚本交互,然后将其发送到后台 - 您可以选择一个。但是当然在 linux 上一切皆有可能。
这里的主要问题是管道(stdout/stderr):你不能只是关闭,脚本很可能会在写入管道端退出本身时出错。因此,您需要重定向现有管道。我不知道任何可以做到这一点的标准工具,但可以使用 gdb 完成。
工作控制也是一个有争议的话题,恕我直言。如果您不是在编写商业脚本,那么在每台服务器上强制执行作业控制可能会更容易,然后进行一些变通方法。但是在这种情况下,您必须知道的唯一一件事是父shell将在退出时向所有子进程发送SIGHUP,因此在这种情况下最好将其关闭,或者使用陷阱忽略它(就像我一样)。
现在,我将描述一种方法来做你想做的事。
首先,确保 gdb 可以附加到从同一用户运行的正在运行的进程。默认情况下,它在许多系统上启用,但有些系统只允许 root 执行此操作。通常您可以通过将 /proc/sys/kernel/yama/ptrace_scope 设置为 0 来更改它(这样做可能不安全)。运行“gdb -p some_pid”检查它是否有效,“some_pid” - 用户运行的任何进程的 PID。
由于 gdb 似乎在从 stding 读取时出现问题,请在系统某处设置一个文件(在我的示例中为 /usr/share/gdb_null_descr),其内容如下:
p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
这将告诉 gdb 在它所附加的进程中将 STDOUT 和 STDERR 重定向到 /dev/null(如果你想保存它,你可以将它更改为任何其他文件,但要小心权限)。
现在,一切都很简单。为了测试,在这个例子中创建一些简单的守护进程,比如 daemon.sh:
#!/bin/bash
success=0;
while [ "$success" -lt 1 ]
do
echo "Give me username!";
read username;
echo "Give me password!";
read password;
if [[ "$username" = "root" && "$password" = "rootpass" ]]
then
success=1;
else
echo "Invalid username/password!";
fi;
done;
echo "Logged in succesfully!";
echo -n > test_file;
loop_count=0;
while [ 1 ]
do
echo "Still working";
if [ "$loop_count" -eq 100 ]
then
loop_count=0;
echo "Please, kill me, I am tired!";
fi;
let loop_count++;
echo "$loop_count" >> test_file;
sleep 1;
done;
现在,我们的期望脚本:
#!/usr/bin/expect
#Just never timeout
set timeout -1;
#Start bash process - we need it only to set trap
spawn bash;
#Set trap on SIGHUP to nothing - bash will just ignore this signal.
send "trap '' HUP;\n";
#Start our half-daemon by replacing this bash process (using exec).
send "exec ./daemon.sh;\n";
#ineract with half-daemon
expect *username!;
send "root\n";
expect *password!;
send "rootpass\n";
#Ok, interaction ends, redirect pipes
system gdb -p [exp_pid] --batch -x /usr/share/gdb_null_descr;
现在,运行 expect 脚本并查看 test_file - 如果每秒都有新条目出现,则妖魔化已成功完成!