Python:生成 sudo 进程(在新终端中),等待完成

发布于 2024-12-05 09:39:56 字数 1480 浏览 1 评论 0原文

编辑:我的最终代码是这样的:

#WARNING: all " in command need to be escaped: \\"
def spawnInNewTerminal(command):
    #creates lock file
    lock = open(lockPath, 'w')
    lock.write("Currently performing task in separate terminal.")
    lock.close()

    #adds line to command to remove lock file
    command += ";rm " + lockPath

    #executes the command in a new terminal
    process = subprocess.Popen (
        ['x-terminal-emulator', '-e',  'sh -c "{0}"'.format(command) ]
        , stdout=subprocess.PIPE )
    process.wait()

    #doesn't let us proceed until the lock file has been removed by the bash command
    while os.path.exists(lockPath):
        time.sleep(0.1)

原始问题:

我正在编写一个简单的包装器,在最终运行 LuaLaTeX 之前“即时”安装任何缺少的包。它基本上可以工作,但接近结束时,我必须运行命令

sudo tlmgr install [string of packages]

,而且,因为不能保证 LaTeX 编辑器将允许用户输入,我必须调用一个新终端来执行此操作,以便他们可以输入 sudo 密码。

我基本上已经弄清楚了:要么

process = subprocess.Popen(
    shlex.split('''x-terminal-emulator -t \'Installing new packages\' -e \'sudo tlmgr install ''' + packagesString + '''\''''), stdout=subprocess.PIPE)
retcode = process.wait()

要么

os.system('''x-terminal-emulator -t \'Installing new packages\' -e \'sudo tlmgr install ''' + packagesString + '''\'''')

唯一的问题是,这条线不会等到生成的终端进程完成。事实上,它会立即继续到下一行(运行实际的 LuaLaTeX),然后用户甚至可以输入密码或下载软件包!

据我了解,这是因为 sudo 子进程立即完成。有没有办法确保 tlmgr 进程在继续之前完成?

Edit: my final code goes something like this:

#WARNING: all " in command need to be escaped: \\"
def spawnInNewTerminal(command):
    #creates lock file
    lock = open(lockPath, 'w')
    lock.write("Currently performing task in separate terminal.")
    lock.close()

    #adds line to command to remove lock file
    command += ";rm " + lockPath

    #executes the command in a new terminal
    process = subprocess.Popen (
        ['x-terminal-emulator', '-e',  'sh -c "{0}"'.format(command) ]
        , stdout=subprocess.PIPE )
    process.wait()

    #doesn't let us proceed until the lock file has been removed by the bash command
    while os.path.exists(lockPath):
        time.sleep(0.1)

Original question:

I am writing a simple wrapper that installs any missing packages "on the fly" before finally running LuaLaTeX. It mostly works, but near the end, I have to run the command

sudo tlmgr install [string of packages]

and furthermore, because there's no guarantee the LaTeX editor will allow user input, I have to call a new terminal to do this in so they can enter their sudo password.

I have mostly figured this out: either

process = subprocess.Popen(
    shlex.split('''x-terminal-emulator -t \'Installing new packages\' -e \'sudo tlmgr install ''' + packagesString + '''\''''), stdout=subprocess.PIPE)
retcode = process.wait()

or

os.system('''x-terminal-emulator -t \'Installing new packages\' -e \'sudo tlmgr install ''' + packagesString + '''\'''')

The only problem is, this line does not wait until the spawned terminal process is done. In fact, it continues to the next line (running the actual LuaLaTeX) immediately, before the user can even enter their password or download the packages!

From what I understand, this is because the sudo child process finishes right away. Is there a way to make sure the tlmgr process finishes before continuing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

三五鸿雁 2024-12-12 09:39:56

原因是 x-terminal-emulator 生成一个新进程并退出,因此您无法知道执行的命令何时实际完成。要解决这个问题,解决方案是修改您的命令以添加另一个通知您的命令。由于 x-terminal-emulator 显然只执行一个命令,因此我们可以使用 shell 来链接它们。
可能不是最好的方法,但其中之一是:

os.system('x-terminal-emulator -t "Installing new packages" -e "sh -c \\"sudo tlmgr install %s; touch /tmp/install_completed\\""' % packagesString)
while not os.path.exists("/tmp/install_completed"):
    time.sleep(0.1)
os.remove("/tmp/install_completed")

The reason is that x-terminal-emulator spawns a new process and exits, so you can't know when the executed command actually finishes. To work around that, a solution would be to modify your command to add another command that notifies you. Since apparently x-terminal-emulator only ever executes one command, we can use a shell to chain them.
Probably not the best way to do, but one would be:

os.system('x-terminal-emulator -t "Installing new packages" -e "sh -c \\"sudo tlmgr install %s; touch /tmp/install_completed\\""' % packagesString)
while not os.path.exists("/tmp/install_completed"):
    time.sleep(0.1)
os.remove("/tmp/install_completed")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文