【问题标题】:How to launch an EDITOR (e. g. vim) from a python script?如何从 python 脚本启动 EDITOR(例如 vim)?
【发布时间】:2011-06-10 16:48:40
【问题描述】:

我想在 python 脚本中调用一个编辑器来征求用户的输入,就像 crontab egit commit 所做的那样。

这是我目前运行的一个 sn-p。 (将来,我可能会使用 $EDITOR 而不是 vim,以便人们可以根据自己的喜好进行自定义。)

tmp_file = '/tmp/up.'+''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
edit_call = [ "vim",tmp_file]
edit = subprocess.Popen(edit_call,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True )   

我的问题是,通过使用 Popen,它似乎使我的 i/o 与 python 脚本无法进入 vim 的运行副本,我找不到将 i/o 传递给 vim 的方法.我收到以下错误。

Vim: Warning: Output is not to a terminal
Vim: Warning: Input is not from a terminal

从 python 调用 CLI 程序、将控制权交给它并在完成后将其传回的最佳方法是什么?

【问题讨论】:

    标签: python vim editor command-line-interface


    【解决方案1】:

    调用 $EDITOR 很容易。我写了这样的代码来调用编辑器:

    import sys, tempfile, os
    from subprocess import call
    
    EDITOR = os.environ.get('EDITOR','vim') #that easy!
    
    initial_message = "" # if you want to set up the file somehow
    
    with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
      tf.write(initial_message)
      tf.flush()
      call([EDITOR, tf.name])
    
      # do the parsing with `tf` using regular File operations.
      # for instance:
      tf.seek(0)
      edited_message = tf.read()
    

    这里的好处是,库处理创建和删除临时文件。

    【讨论】:

    • 太棒了!我的一项修改是在未设置 EDITOR 的情况下添加后备:EDITOR = os.environ.get('EDITOR') if os.environ.get('EDITOR') else 'vim'。如果您愿意接受,我已将其作为修改提交给您。
    • 感谢@sam 和@unutbu 的建议。我不知道你可以摆脱未设置的$EDITOR :)
    • 我必须用with open(tf.name) 重新打开文件才能获得更新的文件内容。否则,我得到的内容与initial_message 相同
    • @progo Mac OSX El Capitan,VIM。有趣
    • 我在读回文件的旧内容时遇到了同样的问题,确实在很多情况下,vim 将旧文件移到一边并写入新文件,而我们的 tf 文件描述符仍然存在在现在备份的文件上打开。在文件名之前添加的命令行选项“+set backupcopy=yes”可以防止这个问题,我现在很高兴能够读取文件的新内容。 call([EDITOR, '+set backupcopy=yes', tf.name])
    【解决方案2】:

    在python3中:'str' does not support the buffer interface

    $ python3 editor.py
    Traceback (most recent call last):
      File "editor.py", line 9, in <module>
        tf.write(initial_message)
      File "/usr/lib/python3.4/tempfile.py", line 399, in func_wrapper
        return func(*args, **kwargs)
    TypeError: 'str' does not support the buffer interface
    

    对于python3,使用initial_message = b""来声明缓冲字符串。

    然后使用edited_message.decode("utf-8")将缓冲区解码为字符串。

    import sys, tempfile, os
    from subprocess import call
    
    EDITOR = os.environ.get('EDITOR','vim') #that easy!
    
    initial_message = b"" # if you want to set up the file somehow
    
    with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
        tf.write(initial_message)
        tf.flush()
        call([EDITOR, tf.name])
    
        # do the parsing with `tf` using regular File operations.
        # for instance:
        tf.seek(0)
        edited_message = tf.read()
        print (edited_message.decode("utf-8"))
    

    结果:

    $ python3 editor.py
    look a string
    

    【讨论】:

    • 接收空白字符。尝试改为 print(edited_message) 会导致 b'' 返回。这是通过 OS X 终端使用 Python 3.5.2
    【解决方案3】:

    python-editor:

    $ pip install python-editor
    $ python
    >>> import editor
    >>> result = editor.edit(contents="text to put in editor\n")
    

    更多详情:https://github.com/fmoo/python-editor

    【讨论】:

      【解决方案4】:

      click 是一个很棒的命令行处理库,它有一些实用程序,click.edit() 是可移植的并且使用 EDITOR 环境变量。我在编辑器中输入了stuff 这一行。请注意,它作为字符串返回。不错。

      (venv) /tmp/editor $ export EDITOR='=mvim -f'
      (venv) /tmp/editor $ python
      >>> import click
      >>> click.edit()
      'stuff\n'
      

      查看文档https://click.palletsprojects.com/en/7.x/utils/#launching-editors 我的全部经验:

      /tmp $ mkdir editor
      /tmp $ cd editor
      /tmp/editor $ python3 -m venv venv
      /tmp/editor $ source venv/bin/activate
      (venv) /tmp/editor $ pip install click
      Collecting click
        Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
      Installing collected packages: click
      Successfully installed click-7.0
      You are using pip version 19.0.3, however version 19.3.1 is available.
      You should consider upgrading via the 'pip install --upgrade pip' command.
      (venv) /tmp/editor $ export EDITOR='=mvim -f'
      (venv) /tmp/editor $ python
      Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:52:21)
      [Clang 6.0 (clang-600.0.57)] on darwin
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import click
      >>> click.edit()
      'stuff\n'
      >>>
      

      【讨论】:

      • 也适用于 Windows。非常好!
      【解决方案5】:

      管道是问题所在。 VIM 是一个依赖于 stdin/stdout 通道是终端而不是文件或管道这一事实的应用程序。删除标准输入/标准输出参数对我有用。

      我会避免使用 os.system,因为它 should 会被子进程模块替换。

      【讨论】:

      • 感谢 dmeister。但是它对我不起作用。我有以下代码。这是你的意思吗? edit_call = [ "vim",tmp_file]; edit = subprocess.Popen(edit_call)
      • @sam 是的,我就是这个意思
      • 运行该代码后,它会启动 vim,但我无法与之交互。输入几个字符后,vim 消失了,剩下的是Vim: Error reading input, exiting...,然后是Vim: Finished.。这让我仍然处于一个过程中。输入空格或回车(还没有提示)后,我得到以下内容,然后返回命令提示符:-bash: 1: command not found
      • 对于未来的用户,也许对于@sam,您只需要在其末尾添加一个.wait()
      【解决方案6】:

      接受的答案对我不起作用。 edited_messageinitial_message 保持一致。正如 cmets 中所解释的,这是由 vim 保存策略引起的。

      有一些可能的解决方法,但它们不能移植到其他编辑器。相反,我强烈建议使用click.edit 函数。有了它,您的代码将如下所示:

      import click
      
      initial_message = "edit me!"
      edited_message = click.edit(initial_message)
      print(edited_message)
      

      Click 是一个第三方库,但如果您正在编写控制台脚本,您可能还是应该使用它。 clickargparserequestsurllib 相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-26
        • 2018-10-15
        • 2011-09-29
        • 2014-02-26
        • 2023-03-27
        • 1970-01-01
        相关资源
        最近更新 更多