如何防止通过su -c调用的bash脚本在SIGINT之后挂起

时间:2014-01-12 11:23:26

标签: bash shell su bash-trap

我有两个脚本。这些都是简化的。 root-script.sh来电userscript.sh

root-script.sh:

 #!/bin/bash 
 su - user1 -c "/user1path/user-script.sh"

user-script.sh:

 #!/bin/bash
 trap 'echo please use x for exit' 2
 while x=0; do
    read -p "enter x for exit:" answer
    if [[ $answer = 'x' ]]; then
            echo "exit now"
            exit 0
    fi
 done

如果我调用user-script.sh它就可以正常工作:

 enter x for exit:
 enter x for exit: ^C_please use x for exit
^C_please use x for exit
x
exit now

如果我将root-script.sh称为root并输入Ctrl-C,我会

 enter x for exit: ^C
Session terminated, killing shell... ...killed.

我回到root-prompt但是提示被阻止了。 使用ps我没有看到root脚本,只看到用户脚本。 如果我终止用户脚本,则根提示符可以再次使用。

如何在SIGINT之后阻止root-script-user-script-construction挂起? 对我来说意味着

  1. 退出root-script.shuser-script.sh
  2. root-script-user-script-construction应该与user-script.sh

    相同
    • bash-version:3.2.51(1)-release(x86_64-suse-linux-gnu)
    • os-version:sles11 3.0.93-0.8-default

2 个答案:

答案 0 :(得分:1)

本文解释了为什么SIGINT没有传递到su -c并提供解决方案:

http://sethmiller.org/it/su-forking-and-the-incorrect-trapping-of-sigint-ctrl-c/

在您的情况下:su - user1 --session-command "/user1path/user-script.sh"

由于--session-command是不鼓励的选项(请参阅man su),如果您感觉不安全,在您的情况下,也可以使用-s选项:

su - user1 -s /user1path/user-script.sh

答案 1 :(得分:0)

我刚刚测试过:

su -c 'trap /bin/true 2; while true; do sleep 1; done' user

su -c 'while true; do sleep 1; done' user

发现前者不能通过SIGINT终止,但后者可以。我的猜测是,也许su -c打开用户的shell来运行-c传递的命令,这就是捕获SIGINT并终止的 - 但是你的脚本只捕获子shell中的SIGINT - 这可能是由父shell的SIGINT处理程序传递SIGTERM。

希望这适合你。

编辑:

su -c 'echo $0; echo $SHELL' user

确认该命令是使用用户的shell运行的。

也许你会找到

su -c 'exec my_script.sh' user

成为更优雅的解决方案。我认为它会起作用,但还没有测试过。 exec会用你的脚本程序替换当前的shell进程,所以我认为它应该可行。

编辑2:

回顾你的问题,我认为你只需要根脚本中的陷阱。或者也许:

exec 'su -c "exec script.sh" user'

如果您想完全继承脚本的陷阱行为。