【问题标题】:Bash: Finally (Try, Except) ExceptionBash:最后(尝试,除外)异常
【发布时间】:2010-10-21 21:45:10
【问题描述】:

我想在 bash 脚本的末尾执行一些命令,即使用户按下 CTRL+C 来取消它的执行。

我知道我可以在另一种编程语言(例如 Python)中运行 bash 脚本,这样我就可以使用“finally”(try-finally)块来执行一些代码。

但是知道 StackOverflow 是一个交流绝妙想法的中心,我想问是否有办法从我的 bash 脚本中做我想做的事情。

那么,有什么想法吗?

编辑:

我想要的是杀死在我的 bash 中打开的每个进程,即 selenium 和 Xvfb 进程。

我尝试将其写入代码:

 trap "selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}');for pid in $selenium_pids; do kill -9 $pid;done; xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}'); for pid in $xvfb_pids; do kill -9 $pid; done" EXIT

但这迫使我在脚本内部每次运行子进程时多次按“CTRL+C”,例如:

Testing nsi.bd.helpcenter ...^C:  --  Total time: 0min 0seg
Testing nsi.bibliography ...^C:  --  Total time: 0min 0seg
Testing nsi.digitallibrary ...^C:  --  Total time: 0min 0seg
Testing nsi.digitallibraryinstaller ...^C:  --  Total time: 0min 1seg
Testing nsi.digitallibraryskins ...^C:  --  Total time: 0min 0seg
....#continues

将陷阱行的结尾从 EXIT 更改为 SIGINT ,如下所示:

trap "selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}');for pid in $selenium_pids; do kill -9 $pid;done; xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}'); for pid in $xvfb_pids; do kill -9 $pid; done" SIGINT

做同样的事情。

现在在第一个 CTRL+C 上退出什么?

因为我试图在字符串的最后添加一个“exit 1”,比如 trap "... ;exit 1"

它在第一个 CTRL+C 上退出,但没有杀死我想要的进程。

想法?

【问题讨论】:

  • 为了可读性和可维护性,将您的陷阱处理程序编写为像 func_name () { ... 这样的多行函数和像这样 trap func_name SIGINT 这样的 trap 语句。不要使用kill -9,除非万不得已 - 首先使用-SIGTERM-SIGQUIT-SIGINT。如果有,请使用 pkill,而不是解析 ps
  • @Dennis 我没有理解您对“多线功能”的意思,但会使用正确的信号来研究 pkill。感谢您的收看。
  • 您发布的答案就是我所说的“多行功能”。

标签: bash execution finally


【解决方案1】:

用这段代码得到了我想要的:

finalize_xvfb_and_selenium() {
    selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}')
    for pid in $selenium_pids; do 
        kill -9 $pid
    done 
    xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}') 
    for pid in $xvfb_pids; do 
        kill -9 $pid
    done
}

finalize_xvfb_and_selenium_and_exit() {
    finalize_xvfb_and_selenium
    echo -e "\n\nXvfb and seleniumrc finalized. Exiting ..."
    exit 13
}

#trap (CTRL+C) signal, to finalize proccess running before exit
trap finalize_xvfb_and_selenium_and_exit SIGINT

我知道有比在任何地方使用kill -9 更好的资源。

【讨论】:

  • 请注意,除了标准信号之外,您还可以使用 Bash 捕获两个伪信号 EXITERR。这些提供了有用的退出包罗万象。
  • 返回码应该从 13 更改为 130 = 128 + 2 (SIGINT),这是被 SIGINT 中断的脚本的常规返回码。这是几个帖子和tldp.org/LDP/abs/html/exitcodes.htm 的标准。
  • @javabrett,抱歉耽搁了。我不再使用代码,所以无法尝试。但是感谢您的考虑并添加到主题中。
【解决方案2】:

你想捕获信号。

当用户在终端点击 control-c 时,操作系统会向当前进程发出 SIGINT。这个信号可以被捕获和处理。你如何做到这一点是一个依赖于 shell 的问题,你应该检查你的 shell 手册页。

请注意,有些信号不能被捕获。尤其是kill -9 发送的 SIGKILL。


根据编辑:bash 可以返回您启动的程序的进程 ID。可以随时捕获所有它们,这样您就不必解析ps 的输出。您也可以考虑向您的孩子发送一些其他信号(可能是 SIGUSR1),这些信号已经设置了陷阱,以便他们递归地杀死 他们的孩子。

说了这么多,你进入了深壳魔法领域。有一些书可能会有所帮助,但我不知道标题是什么。

【讨论】:

  • 这是正确的,但展示如何做可能会使其成为更好的答案
  • @dmckee 谢谢,我会继续寻找。
  • @dmckee @Daenyth 出于好奇,我回答了这个问题。也许你想看看。谢谢你的帮助。
  • @Gabriel:这里的文化接受(并且在某种程度上期望)将自己的答案放在答案中,以便我们可以对它们进行投票。这对您来说是一个优势,因为答案票比问题票更有价值,您可以为一个人获得一张。
  • @dmckee 做到了。谢谢你的课。
猜你喜欢
  • 2014-05-24
  • 2023-03-22
  • 2023-03-30
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多