【问题标题】:Background spawned process in ExpectExpect 中的后台生成进程
【发布时间】:2013-07-28 18:43:53
【问题描述】:

我正在使用 expect 在我的服务器上启动一个应用程序:

#!/usr/bin/expect

set timeout -1

spawn "bin/start-all.sh"
expect {
    -re "Found MongoDB in" { send "y\r"; exp_continue }
    -re "Found Hadoop in" { send "y\r"; exp_continue }
    -re "Going to start Hadoop" { interact }
}

脚本运行时,我可以在几秒钟内访问服务器上的应用程序,但一旦结束,应用程序就变得不可用。

我在调试模式下运行了 expect 并在最后得到以下输出:

expect: does "vendors area. Do you want to start it? [y/n] y\r\n" (spawn_id exp6) match regular expression "Found MongoDB in"? Gate "Found MongoDB in"? gate=no
"Found Hadoop in "? Gate "Found Hadoop in "? gate=no
"Going to start Hadoop"? Gate "Going to start Hadoop"? gate=no
Going to start Hadoop...

expect: does "vendors area. Do you want to start it? [y/n] y\r\nGoing to start Hadoop...\r\n" (spawn_id exp6) match regular expression "Found MongoDB in"? Gate "Found MongoDB in"? gate=no
"Found Hadoop in "? Gate "Found Hadoop in "? gate=no
"Going to start Hadoop"? Gate "Going to start Hadoop"? gate=yes re=yes
expect: set expect_out(0,string) "Going to start Hadoop"
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "vendors area. Do you want to start it? [y/n] y\r\nGoing to start Hadoop"
tty_raw_noecho: was raw = 0  echo = 1
interact: received eof from spawn_id exp6
tty_set: raw = 0, echo = 1
tty_set: raw = 5, echo = 0

我尝试在最后一种模式下使用exit 0interactexp_continuedisconnectsleep 10,以及期待eof,但似乎没有任何效果。我也尝试过运行expect start-all.exp &,但这也不起作用。

当我手动运行 bin/start-all.sh 时,脚本会启动必要的进程然后退出。然而,期望这些进程似乎被杀死了。我该如何解决这个问题?

【问题讨论】:

  • 有很多细节,但不清楚你想要达到什么目的。
  • 这是一个很长的镜头,但你有没有在最后尝试expect eof
  • 恐怕我对这个start-all.sh脚本不熟悉。在 Expect 的 PTY 中运行时,它可能会做一些奇怪的事情,导致它过早终止。
  • 有什么解决办法吗?我有同样的问题:尝试与生成的进程交互,当它到达某个点时,将其背景化并退出。我还在期望脚本中尝试了expect_backgroundexit 0,但没有一个让父期望脚本结束/退出。只有一个中断(CTRL-C)结束它,但我担心它也会中断生成的进程(我不想发生这种情况)。
  • @Lucas,看起来下面的答案已经帮助了几个人。它解决了你的问题吗?如果是,你能接受吗?

标签: shell unix tcl background-process expect


【解决方案1】:

我遇到了同样的问题并解决了这个问题。

expect 退出时,它会向生成的子进程发送SIGHUP(挂断信号)。默认情况下,SIGHUP 会导致生成的进程终止。

如果您希望底层进程不死于SIGHUP,您有两个简单的选择。两者都运作良好:

1) 要求expect 让底层进程忽略spawn 行中的SIGHUP,如下所示:

#!/usr/bin/expect -f
...
spawn -ignore HUP command args...
...
expect_background

2) 自己动手 - 在底层进程本身中忽略 SIGHUP

这是演示方法 2 的工作脚本:

#!/usr/bin/expect -f
#
# start a process and background it after it reaches a certain stage
#
spawn perl -e "\$SIG{HUP} = 'IGNORE'; for (\$a='A';; \$a++) {print qq/value is \$a\\n/; sleep 1;}"

set timeout 600

# Detailed log so we can debug (uncomment to enable)
# exp_internal -f /tmp/expect.log 0

# wait till the subprocess gets to "G"
expect -ex "value is G"

send_user "\n>>> expect: got G\n"

# when we get to G, background the process
expect_background

send_user ">>> spawned process backgrounding successful\n"
exit 0

这是一个运行示例:

$ ./expect-bg
spawn perl -e $SIG{HUP} = 'IGNORE'; for ($a='A';; $a++) {print qq/value is $a\n/; sleep 1;}
value is A
value is B
value is C
value is D
value is E
value is F
value is G

>>> expect: got G
>>> spawned process backgrounding successful

正如在 ps 输出中所预期的那样,perl 进程是后台运行的。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
hankm     6700  0.0  0.0  17696  2984 ?        Ss   18:49   0:00 perl -e $SIG{HUP} = 'IGNORE'; for ($a='A';; $a++) {print qq/value is $a\n/; sleep 1;}

【讨论】:

    【解决方案2】:

    我发现在程序在 Expect 中运行异常的几乎所有情况下都有效的一件事是在屏幕实例中生成一个 shell 并从那里运行程序。

    spawn screen bash
    send "bin/start-all.sh\r"
    

    尝试这样做,看看它是否能解决您过早的 eof 问题。

    【讨论】:

    • 使用此解决方案,您最终可能会在多次执行期望脚本后运行大量屏幕会话。
    • @Bogdan 不一定。根据原始问题,手动运行脚本时,它会在脚本结束时愉快地退出,而不会杀死启动的子进程。如果在 Screen 会话中运行相同的脚本就像手动运行脚本一样,那么您应该能够在最后终止 Screen 会话,而不会终止这些进程。这些 Screen 会话不需要长时间运行。
    猜你喜欢
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2016-03-26
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    相关资源
    最近更新 更多