3

我试图在一个无限循环中运行一个程序,因为它有时会无缘无故地死掉。我希望能够按 Ctrl-C 以防止程序重新启动。

我不希望 Ctrl-C 杀死程序,只是等到它死掉,然后不再重新启动它。

theprogram是一个葡萄酒程序(utorrent)。

告诉我如何制作它的奖励积分,因此它会theprogram像点击右上角的“x”一样安全退出。kill当我从命令行手动或按 Ctrl-C 时,它无法运行其清理代码。因此,我试图阻止它重新启动。

我检查了其他一些关于捕获 SIGINT 的问题,但我不知道如何做到这一点。

任何人都可以修复此代码吗?当按下 Ctrl-C 时,我的代码似乎会杀死theprogram然后退出循环,而不是让theprogram清理。

#!/bin/bash

EXIT=0
trap exiting SIGINT

exiting() { echo "Ctrl-C trapped, will not restart utorrent" ; EXIT=1;}

while [ $EXIT -eq 0 ] ; do
        wine theprogram
        echo "theprogram killed or finished"
        date
        echo "exit code $?"
        echo "sleeping for 20 seconds, then restarting theprogram..."
        sleep 20
done

echo "out of loop"
4

4 回答 4

1

尝试这个:

while true
do
  xterm -e wine theprogram || break
  sleep 3
done

诀窍是通过使用另一个 xterm 来启动 wine。这样酒就有不同的控制终端,不会受到Ctrl-c印刷机的影响。

缺点是你的桌面上会有一个额外的 xterm。您可以使用该选项-iconic将其图标化。

于 2013-11-19T12:43:35.173 回答
1

使用监控流程:

这允许 SIGINT 信号在不影响子进程的情况下命中监视器进程陷阱处理程序。

(这也可以用 perl、python 或任何语言完成)

#!/bin/bash

cmd() {
    trap '' INT
    trap 'echo "Signal USR1 received (pid=$BASHPID)"; EXIT=1' USR1
    EXIT=0
    while [ $EXIT -eq 0 ]
    do
        echo "Starting (pid=$BASHPID)..."
        sleep 5 # represents "wine theprogram"
        echo "theprogram killed or finished"
        date
        echo "Exit code $?"
        if [ $EXIT -eq 0 ]; then
            echo "Sleeping for 2 seconds, then restarting theprogram..."
            sleep 2
        fi
    done
    echo "Exiting (pid=$BASHPID)"
}

run() { cmd & PID=$!; echo Started $PID; }
graceful_exit() { kill -s USR1 $PID && echo "$PID signalled to exit (USR1)"; }
shutdown() { kill -0 $PID 2>/dev/null && echo "Unexpected exit, killing $PID" && kill $PID; }

trap 'graceful_exit' INT
trap 'shutdown' EXIT
run

while :
do
    wait && break
done

echo "Exiting monitor process"
于 2018-01-10T22:20:19.200 回答
1

好吧,我最终没有根据我的问题使用 Ctrl-C ,因为我找不到一个好的解决方案,但我曾经zenity弹出一个框,我可以单击它来退出循环:

zenity 弹出窗口

#!/bin/bash
zenity --info --title "thewineprogram" --text "Hit OK to disable thewineprogram auto-restart" &  # run zenity in the background
zen_pid=$!

while : 
do
    wine <wineprogramlocation>
    EXITCODE=$?
    echo "thewineprog killed or finished"
    echo "exit code was $EXITCODE"
    date

    kill -0 $zen_pid > /dev/null 2>&1  # kill -0 just checks if a pid exists
    if [ $? -eq 1 ] # process does not exist
    then
        break
    fi

    echo "sleeping for 5 seconds, then restarting the wine program..."
    sleep 5     
done

echo "finished"
于 2015-11-05T08:53:11.030 回答
0

看来 SIGINT 上的陷阱必须终止当前正在执行的子命令。唯一的例外似乎是空字符串处理程序。

为了证明这一点:当按下 ctrl-c 时,这(trap "" INT;echo 1;sleep 5;echo 2)不会停止 sleep 命令。然而,这样(trap "echo hi" INT;echo 1;sleep 5;echo 2)做。在此陷阱处理程序执行后,将继续执行后面的命令,特别是“echo 2”。所以空字符串作为处理程序似乎是一种特殊情况,它不会杀死当前的子命令。似乎没有办法运行处理程序而不是杀死当前的子命令。

为什么会这样:Shell forks + execs 来执行每个程序。在系统调用 exec 上,它将信号处理程序重置为其默认行为(调用进程被覆盖,因此处理程序消失了)。忽略的信号被继承(参见“man 2 execve”、“man 7 signal”和 POSIX.1;http: //www.perlmonks.org/?node_id=1198044 )

我有第二个想法:使用 'trap "" INT' 完全禁用 ctrl-c,然后将 ctrl-z 作为信号以优雅地退出程序。仅捕获 ctrl-z (STP) 对我来说似乎无法正常工作。当我运行 '(trap "echo test" TSTP;sleep 5)' 并按 ctrl-z 时,我的 shell 挂起。sleep 在 5 秒后永远不会完成,奇怪的是 ctrl-c 不再起作用。除了 ctrl-c 和 ctrl-z 之外,我不知道可以使用任何其他热键信号。这是已知行为:请参阅Bash 脚本:无法正确处理 SIGTSTP

于 2018-01-10T18:38:36.787 回答