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


当前回答

最多案例:

在大多数情况下,一个短片的代码,如此,是你将需要的一切:

import subprocess
import shlex

source = "test.txt"
destination = "test_copy.txt"

base = "cp {source} {destination}'"
cmd = base.format(source=source, destination=destination)
subprocess.check_call(shlex.split(cmd))

它是干净和简单的。

subprocess.check_call 以论点运行命令,等待命令完成。 shlex.split 使用 shell-like syntax 分割行 cmd

其他案例:

如果这不适用于某些特定的命令,最有可能你有一个问题与命令线的解释器. 操作系统选择了默认一个不适合你的程序类型或可能没有找到适当的一个在系统可执行的路径。

例子:

使用Unix系统上的转向操作器

input_1 = "input_1.txt"
input_2 = "input_2.txt"
output = "merged.txt"
base_command = "/bin/bash -c 'cat {input} >> {output}'"

base_command.format(input_1, output=output)
subprocess.check_call(shlex.split(base_command))

base_command.format(input_2, output=output)
subprocess.check_call(shlex.split(base_command))

正如《Python Zen: Explicit is better than implicit》中所说的那样。

因此,如果使用 Python >=3.6 函数,它会看起来像这样:

import subprocess
import shlex

def run_command(cmd_interpreter: str, command: str) -> None:
    base_command = f"{cmd_interpreter} -c '{command}'"
    subprocess.check_call(shlex.split(base_command)

其他回答

我总是使用纺织品来做这些事情,这里是一个演示代码:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

但这似乎是一个很好的工具:sh(Python子处理界面)。

看看一个例子:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

这里有很多答案,但没有一个满足了我所有的需求。

我需要运行命令并捕获输出和输出代码. 我需要时间out 执行的程序,并强迫它出去,如果时间out 达到,并杀死它的所有儿童过程. 我需要它在 Windows XP 和以后, Cygwin 和 Linux 工作。

def _run(command, timeout_s=False, shell=False):
    ### run a process, capture the output and wait for it to finish. if timeout is specified then Kill the subprocess and its children when the timeout is reached (if parent did not detach)
    ## usage: _run(arg1, arg2, arg3)
        # arg1: command + arguments. Always pass a string; the function will split it when needed
        # arg2: (optional) timeout in seconds before force killing
        # arg3: (optional) shell usage. default shell=False
    ## return: a list containing: exit code, output, and if timeout was reached or not

    # - Tested on Python 2 and 3 on Windows XP, Windows 7, Cygwin and Linux.
    # - preexec_fn=os.setsid (py2) is equivalent to start_new_session (py3) (works on Linux only), in Windows and Cygwin we use TASKKILL
    # - we use stderr=subprocess.STDOUT to merge standard error and standard output
    import sys, subprocess, os, signal, shlex, time

    def _runPY3(command, timeout_s=None, shell=False):
        # py3.3+ because: timeout was added to communicate() in py3.3.
        new_session=False
        if sys.platform.startswith('linux'): new_session=True
        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, start_new_session=new_session, shell=shell)

        try:
            out = p.communicate(timeout=timeout_s)[0].decode('utf-8')
            is_timeout_reached = False
        except subprocess.TimeoutExpired:
            print('Timeout reached: Killing the whole process group...')
            killAll(p.pid)
            out = p.communicate()[0].decode('utf-8')
            is_timeout_reached = True
        return p.returncode, out, is_timeout_reached

    def _runPY2(command, timeout_s=0, shell=False):
        preexec=None
        if sys.platform.startswith('linux'): preexec=os.setsid
        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=preexec, shell=shell)

        start_time = time.time()
        is_timeout_reached = False
        while timeout_s and p.poll() == None:
            if time.time()-start_time >= timeout_s:
                print('Timeout reached: Killing the whole process group...')
                killAll(p.pid)
                is_timeout_reached = True
                break
            time.sleep(1)
        out = p.communicate()[0].decode('utf-8')
        return p.returncode, out, is_timeout_reached

    def killAll(ParentPid):
        if sys.platform.startswith('linux'):
            os.killpg(os.getpgid(ParentPid), signal.SIGTERM)
        elif sys.platform.startswith('cygwin'):
            # subprocess.Popen(shlex.split('bash -c "TASKKILL /F /PID $(</proc/{pid}/winpid) /T"'.format(pid=ParentPid)))
            winpid=int(open("/proc/{pid}/winpid".format(pid=ParentPid)).read())
            subprocess.Popen(['TASKKILL', '/F', '/PID', str(winpid), '/T'])
        elif sys.platform.startswith('win32'):
            subprocess.Popen(['TASKKILL', '/F', '/PID', str(ParentPid), '/T'])

    # - In Windows, we never need to split the command, but in Cygwin and Linux we need to split if shell=False (default), shlex will split the command for us
    if shell==False and (sys.platform.startswith('cygwin') or sys.platform.startswith('linux')):
        command=shlex.split(command)

    if sys.version_info >= (3, 3): # py3.3+
        if timeout_s==False:
            returnCode, output, is_timeout_reached = _runPY3(command, timeout_s=None, shell=shell)
        else:
            returnCode, output, is_timeout_reached = _runPY3(command, timeout_s=timeout_s, shell=shell)
    else:  # Python 2 and up to 3.2
        if timeout_s==False:
            returnCode, output, is_timeout_reached = _runPY2(command, timeout_s=0, shell=shell)
        else:
            returnCode, output, is_timeout_reached = _runPY2(command, timeout_s=timeout_s, shell=shell)

    return returnCode, output, is_timeout_reached

然后用它如下:

总是将命令作为一个行(它更容易)。你不需要分开它;函数在需要时将分开它。

所以我们可以用这个类似的时间:

a=_run('cmd /c echo 11111 & echo 22222 & calc',3)
for i in a[1].splitlines(): print(i)

或者没有时间:

b=_run('cmd /c echo 11111 & echo 22222 & calc')

更多例子:

b=_run('''wmic nic where 'NetConnectionID="Local Area Connection"' get NetConnectionStatus /value''')
print(b)

c=_run('cmd /C netsh interface ip show address "Local Area Connection"')
print(c)

d=_run('printf "<%s>\n" "{foo}"')
print(d)

你也可以指定Shell=True,但在大多数情况下,这个功能是无用的。我宁愿自己选择我想要的Shell,但这里是,如果你也需要它:

# windows
e=_run('echo 11111 & echo 22222 & calc',3, shell=True)
print(e)
# Cygwin/Linux:
f=_run('printf "<%s>\n" "{foo}"', shell=True)
print(f)

為什麼我沒有使用更簡單的新方法 subprocess.run()?

因为它支持在Python 3.7+,但最后支持的Python版本在Windows XP是3.4. 而且由于这个功能的Timeout论点在Windows中是无用的,它不会杀死执行命令的儿童过程. 如果你使用 capture_output + Timeout论点,它会挂在如果有一个儿童过程仍然运行。

下面是如何呼叫外部程序的概述,包括其优点和缺点:

os.system 将命令和论点转移到您的系统的阴道. 这很好,因为您实际上可以以这种方式同时运行多个命令,并设置管道和输入/输出重定向。 例如: os.system(“some_command < input_file♰ another_command > output_file”) 但是,虽然这是方便的,您必须手动处理阴道字符的逃避,如空间,和

副过程模块应该是你所使用的。

最后,请注意,对于你通过的所有方法,最终命令将由丝带执行,你负责逃避它。 有严重的安全影响,如果你通过的丝带的任何部分不能完全信任。 例如,如果用户进入某些 / 任何部分的丝带. 如果你不确定,只使用这些方法的连续。

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

想象一下,用户输入了一些“我的妈妈不喜欢我&rm -rf /”可以删除整个文件系统。

import os
os.system("your command")

请注意,这是危险的,因为命令没有清理,我将其留给谷歌有关“骨”和“骨”模块的文档,有许多功能(exec*和spawn*)将做类似的事情。

使用Python模块的Popen函数是运行Linux命令的最简单方式,Popen.communicate()函数将为您的命令提供输出。

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..