我如何在Python中命名一个外部命令,就好像我把它写在一个<unk>或命令中?


当前回答

在Python中呼叫外部命令

一个简单的方式来呼叫一个外部命令是使用os.system(...). 这个功能返回命令的输出值. 但缺点是我们不会得到 stdout 和 stderr。

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'

在背景下在Python中呼叫外部命令

subprocess.Popen 提供更多的灵活性运行一个外部命令而不是使用 os.system. 我们可以在背景下启动一个命令,等待它完成。

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out

在背景下在Python中呼叫一个长期运行的外部命令,并在一段时间后停止

我们甚至可以在背景下开始一个漫长的运行过程,使用subprocess.Popen,并在任务完成后一次杀死它。

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]

其他回答

Invoke 是一个 Python (2.7 和 3.4+) 任务执行工具和图书馆. 它提供清洁,高级别的 API 运行 Shell 命令:

>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1

os.system 不允许您存储结果,所以如果您想要存储结果在某些列表或某些东西,一个 subprocess.call 工作。

假设你想从一个 CGI 脚本开始一个漫长的任务,也就是说,孩子的过程应该比 CGI 脚本执行过程更长。

从子过程模块文档的经典例子是:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

我的目标平台是FreeBSD,但开发是在Windows上,所以我首先面对了Windows上的问题。

在Windows(Windows XP)上,父母过程不会完成,直到 longtask.py 完成了工作。 这不是你想要的 CGI 脚本. 问题不是具体的 Python; 在 PHP 社区,问题是相同的。

解决方案是将 DETACHED_PROCESS Process Creation Flag 转移到 Windows API 中的 CreateProcess 功能。 如果您安装了 pywin32,您可以从 win32 过程模块中导入旗帜,否则您应该自己定义:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

我没有在其他平台上检查代码,也不知道FreeBSD的行为原因,如果有人知道的话,请分享你的想法。

还有铅

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

经过一些研究,我有下面的代码,这对我来说非常好,它基本上在实时打印了标准输出和标准错误。

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while True:
        out = pipe.stdout.read(1)
        stdout_result = pipe.poll()
        if out == '' and stdout_result is not None:
            break

        if out != '':
            sys.stdout.write(out)
            sys.stdout.flush()


def stderr_thread(pipe):
    global stderr_result
    while True:
        err = pipe.stderr.read(1)
        stderr_result = pipe.poll()
        if err == '' and stderr_result is not None:
            break

        if err != '':
            sys.stdout.write(err)
            sys.stdout.flush()


def exec_command(command, cwd=None):
    if cwd is not None:
        print '[' + ' '.join(command) + '] in ' + cwd
    else:
        print '[' + ' '.join(command) + ']'

    p = subprocess.Popen(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
    )

    out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
    err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))

    err_thread.start()
    out_thread.start()

    out_thread.join()
    err_thread.join()

    return stdout_result + stderr_result