如何用sudo杀死用Popen调用的shell脚本?

2024-10-01 11:20:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我用Python编写了一个gtkgui应用程序,只需调用一个shell脚本,并将调用参数从GUI传递给脚本,并在文本窗口中返回脚本结果。在

现在我想允许用户从GUI中取消正在运行的shell脚本。脚本以Popen开头。如果我以普通用户的身份调用它,它可以正常工作(在下面的代码中标记sudo=False)。当我使用sudo调用脚本时,我不能再取消它了。我发现如果我使用shell=True,那么报告kill的人就不起作用了,所以我用shell=False测试了它,但是它也不起作用。在

我将问题归结为以下代码片段:

import os
import signal
import subprocess
import time
import sys
import shlex

bashScriptFileName="t.sh"

f = open(bashScriptFileName,'w')

f.write("""#!/bin/bash
on_die()
{
    echo "Dying..."
    exit 0
}  

trap 'on_die' TERM

SEC=0
while true ; do
    sleep 1
    SEC=$((SEC+1))
    echo "I'm PID# $$, and I'm alive for $SEC seconds now!"
done

exit 0""")
f.close()
os.chmod(bashScriptFileName, 0755)

shell=True      # flag to enable/disable shell invocation of Popen
sudo=True       # flag to invoke command with sudo

if sudo:
    commandToExecute='sudo -S '+ bashScriptFileName
else:
    commandToExecute='./' + bashScriptFileName

if not shell:
    commandToExecute = shlex.split(commandToExecute)

print "Command: %s" % (commandToExecute)                                

proc = subprocess.Popen(commandToExecute, stdin=subprocess.PIPE, close_fds=False,shell=shell, preexec_fn=os.setsid)
print >> proc.stdin, "secretPassword"                
print 'PARENT      : Pausing before sending signal to child %s...' % proc.pid
sys.stdout.flush()
time.sleep(5)
print 'PARENT      : Signaling child %s' % proc.pid
sys.stdout.flush()
os.killpg(proc.pid, signal.SIGTERM)
time.sleep(3)
print "Done"

事实上,作为一个普通用户,我已经遇到了一些问题os.杀死但后来发现我不得不用操作系统集UID然后杀了那个跑来跑去的炮弹。我是线程新手,从我的角度来看,这可能只是一个简单的Linux线程错误。。。在


Tags: import脚本falsetruesignalossudosec
2条回答

TL;DR

处理此问题的一种更优雅的方法是使用pyexpect启动进程,而不是使用“子流程.Popen". 在

spawnProcess = pexpect.spawn(command)

然后,当您想“终止”进程时,您只需:

^{pr2}$

说明:

正在运行sudo kill操作系统是一种肮脏的黑客行为,需要用户再次输入密码,或者要求您存储根密码以允许您终止子进程。在我的例子中,情况更糟,因为进程不是用sudo启动的,而是setuidroot可执行文件,所以目标用户实际上没有sudo访问权限。在

事实证明,bash中的“CTRL+C”与kill-INT不同,因为很多人会让你相信。您可以使用sudo或setuidroot“CTRL+C”启动进程,但不能向进程发送SIGINT。我在这里找到了解释:

https://www.reddit.com/r/linux/comments/2av912/how_does_sudo_get_signals_from_the_controlling/ciz574v

我知道只有“CTRL+C”才能真正起作用,所以我设计了一个解决方案,模仿用户的操作,它就像一个符咒!在

如果你用sudo启动它,你必须拥有root权限才能杀死它。基本上,你必须:

os.system("sudo kill %d"%(pid))

另外,出于安全考虑,我建议您将bash脚本创建为root,将其放在任何方便的地方,不给用户写访问权限,最后设置sudo来运行它,而不需要密码。这样就不需要在这个python脚本中存储密码了。在

相关问题 更多 >