Python3/Linux在默认编辑器中打开文本文件并等待完成

2024-03-28 08:15:17 发布

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

我需要等待用户在默认图形应用程序(Debian和derivates)中编辑完文本文件

如果将xdg open与subprocess.call一起使用(通常等待),则在编辑器中打开文件后,它将继续。我假设是因为xdg open本身异步启动编辑器

通过检索text/plain mime类型的启动程序,并将其与Gio.DesktopAppInfo.new一起使用,我最终获得了一个或多或少可以工作的代码,以获取编辑器的命令。前提是编辑器尚未打开,在这种情况下,进程将在编辑器仍打开时结束

我添加了检查process.pid和进程轮询的解决方案。两者都以无限循环结束

等待过程完成似乎是一种过于复杂的方式。那么,有没有更可靠的方法来实现这一点

#! /usr/bin/env python3

import subprocess
from gi.repository import Gio
import os
from time import sleep
import sys


def open_launcher(my_file):
    print('launcher open')
    app = subprocess.check_output(['xdg-mime', 'query', 'default', 'text/plain']).decode('utf-8').strip()
    print(app)
    launcher = Gio.DesktopAppInfo.new(app).get_commandline().split()[0]
    print(launcher)
    subprocess.call([launcher, my_file])
    print('launcher close')
    
def open_xdg(my_file):
    print('xdg open')
    subprocess.call(['xdg-open', my_file])
    print('xdg close')
    
def check_pid(pid):        
    """ Check For the existence of a unix pid. """
    try:
        os.kill(int(pid), 0)
    except OSError:
        return False
    else:
        return True
    
def open_pid(my_file):
    pid = subprocess.Popen(['xdg-open', my_file]).pid
    while check_pid(pid):
        print(pid)
        sleep(1)
        
def open_poll(my_file):
    proc = subprocess.Popen(['xdg-open', my_file])
    while not proc.poll():
        print(proc.poll())
        sleep(1)
        
def open_ps(my_file):
    subprocess.call(['xdg-open', my_file])
    pid = subprocess.check_output("ps -o pid,cmd -e | grep %s | head -n 1 | awk '{print $1}'" % my_file, shell=True).decode('utf-8')
    while check_pid(pid):
        print(pid)
        sleep(1)
        
def open_popen(my_file):
    print('popen open')
    process = subprocess.Popen(['xdg-open', my_file])
    process.wait()
    print(process.returncode)
    print('popen close')


# This will end the open_xdg function while the editor is open.
# However, if the editor is already open, open_launcher will finish while the editor is still open.
#open_launcher('test.txt')

# This solution opens the file but the process terminates before the editor is closed.
#open_xdg('test.txt')

# This will loop indefinately printing the pid even after closing the editor.
# If you check for the pid in another terminal you see the pid with: [xdg-open] <defunct>.
#open_pid('test.txt')

# This will print None once after which 0 is printed indefinately: the subprocess ends immediately.
#open_poll('test.txt')

# This seems to work, even when the editor is already open.
# However, I had to use head -n 1 to prevent returning multiple pids.
#open_ps('test.txt')

# Like open_xdg, this opens the file but the process terminates before the editor is closed.
open_popen('test.txt')

Tags: thetestismydefcheckopenprocess
1条回答
网友
1楼 · 发布于 2024-03-28 08:15:17

您可以使用^{}等待子进程终止,而不是尝试轮询PID:

Wait for child process to terminate. Set and return returncode attribute.

此外,获取get_commandline()的第一部分并不保证是启动器。由get_commandline()返回的字符串将匹配the ^{} key spec,这意味着返回字符串中的%u%U%f%F字段代码应替换为正确的值

下面是一些基于xdg-mime方法的示例代码:

#!/usr/bin/env python3
import subprocess
import shlex
from gi.repository import Gio

my_file = 'test.txt'

# Get default application
app = subprocess.check_output(['xdg-mime', 'query', 'default', 'text/plain']).decode('utf-8').strip()

# Get command to run
command = Gio.DesktopAppInfo.new(app).get_commandline()

# Handle file paths with spaces by quoting the file path
my_file_quoted = "'" + my_file + "'"

# Replace field codes with the file path
# Also handle special case of the atom editor
command = command.replace('%u', my_file_quoted)\
    .replace('%U', my_file_quoted)\
    .replace('%f', my_file_quoted)\
    .replace('%F', my_file_quoted if app != 'atom.desktop' else ' wait ' + my_file_quoted)

# Run the default application, and wait for it to terminate
process = subprocess.Popen(
    shlex.split(command), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
process.wait()

# Now the exit code of the text editor process is available as process.returncode

我对我的示例代码有几点意见

备注1:处理文件路径中的空格

要打开的文件路径必须用引号括起来,否则shlex.split(command)将在空格上拆分文件名

注释2:转义字符

{a3}国家

Literal percentage characters must be escaped as %%.

然后,我使用replace()可能会替换转义的%字符。为简单起见,我选择忽略此边缘情况

备注3:原子

我假设期望的行为是一直等到图形编辑器关闭。对于atom文本编辑器,除非提供了 wait选项,否则它将在启动窗口时立即终止。因此,如果默认编辑器是atom,我会有条件地添加 wait选项

备注4:subprocess.DEVNULL

^{}在python 3.3中是新的。对于较旧的python版本,可以使用以下内容:

with open(os.devnull, 'w') as DEVNULL:
    process = subprocess.Popen(
        shlex.split(command), stdout=DEVNULL, stderr=DEVNULL)

测试

我用GNOME桌面环境在Ubuntu上测试了上面的示例代码。我使用以下图形文本编辑器进行了测试:geditmousepadatom

相关问题 更多 >