17.1. 子流程-子流程 Management

2.4 版的新Function。

subprocess模块允许您生成新进程,连接到它们的 Importing/输出/错误管道,并获取它们的返回代码。该模块旨在替换一些较旧的模块和Function:

os.system
os.spawn*
os.popen*
popen2.*
commands.*

可以在subprocess-replacements部分中找到有关如何使用该模块替换旧Function的信息。

See also

强烈建议 POSIX 用户(Linux,BSD 等)安装和使用更新得多的subprocess32模块,而不是 python 2.7 附带的版本。在许多情况下,这是一种替换,但具有更好的行为。

PEP 324 – PEP 建议子流程模块

17.1.1. 使用子流程模块

建议的启动子流程的方法是使用以下便捷Function。对于无法满足您需求的更高级用例,请使用基础的Popen接口。

  • subprocess. call(* args **,* stdin = None stdout = None stderr = None shell = False *)
    • 运行* args *描述的命令。await 命令完成,然后返回returncode属性。

上面显示的参数仅是最常见的参数,下面在常用参数中进行了描述(因此缩写签名中的符号略有奇怪)。完整的函数签名与Popen构造函数的签名相同-该函数将所有提供的参数直接传递到该接口。

Examples:

>>> subprocess.call(["ls", "-l"])
0

>>> subprocess.call("exit 1", shell=True)
1

Warning

使用shell=True可能会带来安全隐患。有关详细信息,请参见常用参数下的警告。

Note

请勿将stdout=PIPEstderr=PIPE与此Function一起使用,因为这会根据子进程的输出量而死锁。需要管道时,请将Popencommunicate()方法一起使用。

  • subprocess. check_call(* args **,* stdin = None stdout = None stderr = None shell = False *)

上面显示的参数仅是最常见的参数,下面在常用参数中进行了描述(因此缩写签名中的符号略有奇怪)。完整的函数签名与Popen构造函数的签名相同-该函数将所有提供的参数直接传递到该接口。

Examples:

>>> subprocess.check_call(["ls", "-l"])
0

>>> subprocess.check_call("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

2.5 版的新Function。

Warning

使用shell=True可能会带来安全隐患。有关详细信息,请参见常用参数下的警告。

Note

请勿将stdout=PIPEstderr=PIPE与此Function一起使用,因为这会根据子进程的输出量而死锁。需要管道时,请将Popencommunicate()方法一起使用。

  • subprocess. check_output(* args **,* stdin = None stderr = None shell = False universal_newlines = False *)
    • 运行带有参数的命令,并以字节字符串形式返回其输出。

如果返回码非零,则会引发CalledProcessErrorCalledProcessError对象将在returncode属性中具有返回码,在output属性中具有任何输出。

上面显示的参数仅是最常见的参数,下面在常用参数中进行了描述(因此缩写签名中的符号略有奇怪)。完整函数签名与Popen构造函数的签名基本相同,除了* stdout *在内部使用外,这是不允许的。所有其他提供的参数将直接传递到Popen构造函数。

Examples:

>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'

>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

要还捕获结果中的标准错误,请使用stderr=subprocess.STDOUT

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
'ls: non_existent_file: No such file or directory\n'

2.7 版的新Function。

Warning

使用shell=True可能会带来安全隐患。有关详细信息,请参见常用参数下的警告。

Note

请勿将此函数与stderr=PIPE一起使用,因为它会根据子进程错误量而死锁。需要 stderr 管道时,请将Popencommunicate()方法一起使用。

  • subprocess. PIPE

    • 可以用作Popen的* stdin stdout stderr *参数的特殊值,它指示应打开到标准流的管道。
  • subprocess. STDOUT

    • 可以用作Popen的* stderr *参数的特殊值,它指示标准错误应与标准输出进入同一句柄。
  • exception subprocess. CalledProcessError

  • returncode

    • 子进程的退出状态。
  • cmd

    • 用于产生子进程的命令。
  • output

    • 如果此异常由check_output()引发,则子进程的输出。否则,None

17.1.1.1. 常用参数

为了支持各种用例,Popen构造函数(和便捷函数)接受大量可选参数。对于大多数典型用例,可以安全地将其中许多参数保留为其默认值。最常用的参数是:

Note

  • args 是所有调用所必需的,应为字符串或程序参数序列。通常最好提供一个参数序列,因为它允许模块处理任何必需的参数转义和引用(例如,允许在文件名中留空格)。如果传递单个字符串,则 shell *必须为True(请参见下文),否则该字符串必须简单地命名要执行的程序而无需指定任何参数。

  • stdin stdout stderr 分别指定执行程序的标准 Importing,标准输出和标准错误文件句柄。有效值为PIPE,现有文件 Descriptors(正整数),现有文件对象和NonePIPE表示应创建到子级的新管道。使用None的默认设置,将不会发生重定向。子级的文件句柄将从父级继承。另外, stderr *可以为STDOUT,这表示子进程的 stderr 数据应捕获到与 stdout 相同的文件句柄中。

如果* stdout stderr 是管道,而 universal_newlines *是True,则所有行尾都将转换为'\n',如open()universal newlines 'U' mode 参数所述。

如果* shell *是True,则指定的命令将pass shell 执行。如果您主要将 Python 用于大多数系统 Shell 程序提供的增强控制流,并且仍然希望方便地访问其他 Shell 程序Function(例如 Shell 程序管道,文件名通配符,环境变量扩展以及将~扩展到用户的家),则这很有用。目录。但是,请注意,Python 本身提供了许多类似 shell 的Function(特别是globfnmatchos.walk()os.path.expandvars()os.path.expanduser()shutil)的实现。

Warning

执行包含来自不受信任来源的未经验证的 Importing 的 shell 命令会使程序容易受到shell injection的攻击,这是一个严重的安全漏洞,可能导致任意命令执行。因此,强烈建议不要从外部 Importing 构造命令字符串的情况下使用shell=True

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

shell=False禁用所有基于 shell 的Function,但不会遭受此漏洞的影响;有关使shell=False工作的有用提示,请参见Popen构造函数文档中的 Comments。

使用shell=True时,可以使用pipes.quote()来适当地转义将用于构造 Shell 命令的字符串中的空格和 Shell 元字符。

Popen构造函数文档中对这些选项以及所有其他选项进行了详细说明。

17.1.1.2. Popen 构造函数

该模块中的基础流程创建和 Management 由Popen类处理。它提供了很大的灵 Active,以便开发人员能够处理便捷Function未涵盖的不太常见的情况。

    • class * subprocess. Popen((args bufsize = 0 executable = None stdin = None stdout = None stderr = None preexec_fn = None close_fds = False shell = False cwd = None env = None universal_newlines = False startupinfo = None creationflags = 0 *)
    • 在新进程中执行子程序。在 Unix 上,该类使用类似os.execvp()的行为来执行子程序。在 Windows 上,该类使用 Windows CreateProcess()函数。 Popen的参数如下。
  • args 应该是程序参数的序列,或者是单个字符串。默认情况下,如果 args 是序列,则要执行的程序是 args 中的第一项。如果 args 是字符串,则解释取决于平台,并在下面进行描述。有关默认行为的其他区别,请参见 shell executable 参数。除非另有说明,否则建议将 args *作为序列传递。

在 Unix 上,如果* args *是字符串,则该字符串将解释为要执行的程序的名称或路径。但是,只有在不将参数传递给程序的情况下才能执行此操作。

Note

在确定* args *的正确标记化时,shlex.split()很有用,尤其是在复杂情况下:

>>> import shlex, subprocess
>>> command_line = raw_input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print args
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!

特别要注意的是,在 Shell 程序中由空格分隔的选项(例如* -input )和参数(例如 eggs.txt )位于单独的列表元素中,而在参数中使用引号或反斜杠转义的参数 Shell 程序(例如,包含空格的文件名或上面显示的 echo *命令)是单个列表元素。

在 Windows 上,如果* args *是一个序列,它将以在 Windows 上将参数序列转换为字符串中描述的方式转换为字符串。这是因为基础CreateProcess()对字符串进行操作。

  • shell 参数(默认为False)指定是否将 shell 用作要执行的程序。如果 shell True,建议将 args *作为字符串而不是序列传递。

在带有shell=True的 Unix 上,shell 默认为/bin/sh。如果* args 是字符串,则该字符串指定要pass Shell 执行的命令。这意味着字符串的格式必须与在 shell 提示符下键入时的格式完全相同。例如,这包括在文件名中使用引号或反斜杠转义。如果 args *是序列,则第一项指定命令字符串,任何其他项将被视为 shell 本身的其他参数。也就是说,Popen等效于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在具有shell=True的 Windows 上, COMSPEC环境变量指定默认 Shell 程序。在 Windows 上唯一需要指定shell=True的是 Shell 中内置了要执行的命令(例如 dircopy )。您不需要shell=True即可运行批处理文件或基于控制台的可执行文件。

Warning

如果与不可信的 Importing 结合使用,则传递shell=True可能会带来安全隐患。有关详细信息,请参见常用参数下的警告。

如果指定了* bufsize ,其含义与内置 open()函数的相应参数相同:0表示未缓冲,1表示行缓冲,任何其他正值表示使用(大约)该大小的缓冲区。负的 bufsize *表示使用系统默认值,通常表示完全缓冲。 * bufsize *的默认值为0(无缓冲)。

Note

如果遇到性能问题,建议您trypass将* bufsize *设置为-1 或足够大的正值(例如 4096)来启用缓冲。

  • executable 参数指定要执行的替换程序。很少需要。当shell=False时, executable 替换要由 args 指定的程序。但是,原始的 args 仍会传递给程序。大多数程序将 args 指定的程序视为命令名称,然后该名称可能与实际执行的程序不同。在 Unix 上, args 名称成为 Util(例如 ps )中可执行文件的显示名称。如果shell=True,在 Unix 上, executable *参数指定默认/bin/sh的替换 Shell。

  • stdin stdout stderr 分别指定执行程序的标准 Importing,标准输出和标准错误文件句柄。有效值为PIPE,现有文件 Descriptors(正整数),现有文件对象和NonePIPE表示应创建到子级的新管道。使用None的默认设置,将不会发生重定向。子级的文件句柄将从父级继承。另外, stderr *可以为STDOUT,这表示子进程的 stderr 数据应捕获到与 stdout 相同的文件句柄中。

如果将* preexec_fn *设置为可调用对象,则将在子进程执行之前在子进程中调用该对象。 (仅 Unix)

如果* close_fds 为 true,则在执行子进程之前,将关闭除012之外的所有文件 Descriptors。 (仅限 Unix)。或者,在 Windows 上,如果 close_fds 为 true,则子进程将不会继承任何句柄。请注意,在 Windows 上,不能将 close_fds 设置为 true,也不能pass设置 stdin stdout stderr *来重定向标准句柄。

如果* cwd 不是None,则子级的当前目录将在执行前更改为 cwd 。请注意,搜索可执行文件时不会考虑此目录,因此您无法指定程序相对于 cwd *的路径。

如果* env *不是None,则它必须是为新进程定义环境变量的 Map;使用它们而不是继承当前流程的环境,这是默认行为。

Note

如果指定,* env 必须提供程序执行所需的任何变量。在 Windows 上,要运行side-by-side assembly,必须 env *必须包含有效的 SystemRoot

如果* universal_newlines True,则文件对象 stdout stderr *在universal newlines模式下作为文本文件打开。行可以pass'\n'(Unix 的行尾约定),'\r'(旧的 Macintosh 约定)或'\r\n'(Windows 约定)中的任何一个终止。所有这些外部表示在 Python 程序中都被视为'\n'

Note

仅当 Python 构建为具有通用换行符支持(默认设置)时,此Function才可用。另外,文件对象stdoutstdinstderr的换行属性不会pass communication()方法进行更新。

如果给定,则* startupinfo *将是一个STARTUPINFO对象,该对象将传递给基础CreateProcess函数。 * creationflags *(如果提供)可以是CREATE_NEW_CONSOLECREATE_NEW_PROCESS_GROUP。 (仅 Windows)

17.1.1.3. Exceptions

在新程序开始执行之前,子进程中引发的异常将在父进程中重新引发。另外,异常对象将具有一个名为child_traceback的额外属性,该属性是一个字符串,其中包含从孩子的角度出发的回溯信息。

引发的最常见异常是OSError。例如,在try执行不存在的文件时,就会发生这种情况。应用程序应为OSErrorexception 做好准备。

如果使用无效参数调用Popen,则会引发ValueError

如果被调用的进程返回一个非零的返回码,则check_call()check_output()将提高CalledProcessError

17.1.1.4. Security

与其他一些 popen 函数不同,此实现永远不会隐式调用系统 Shell。这意味着所有字符,包括 Shell 元字符,都可以安全地传递给子进程。显然,如果显式调用了 shell,则应用程序有责任确保所有空白和元字符都被正确引用。

17.1.2. Popen 对象

Popen类的实例具有以下方法:

  • Popen. poll ( )

    • 检查子进程是否已终止。设置并返回returncode属性。
  • Popen. wait ( )

    • await 子进程终止。设置并返回returncode属性。

Warning

当使用stdout=PIPE和/或stderr=PIPE时,这将导致死锁,并且子进程会向管道生成足够的输出,从而阻塞 awaitOS 管道缓冲区接受更多数据的 await。使用communicate()可以避免这种情况。

  • Popen. communicate(* input = None *)
    • 与进程交互:将数据发送到 stdin。从 stdout 和 stderr 读取数据,直到到达文件末尾。await 进程终止。可选的* input *参数应为要发送给子进程的字符串,如果没有数据应发送给子进程,则为None

communicate()返回一个 Tuples(stdoutdata, stderrdata)

请注意,如果要将数据发送到进程的 stdin,则需要使用stdin=PIPE创建 Popen 对象。同样,要在结果 Tuples 中获得None以外的任何内容,您也需要提供stdout=PIPE和/或stderr=PIPE

Note

读取的数据缓存在内存中,因此,如果数据大小很大或没有限制,请不要使用此方法。

  • Popen. send_signal(* signal *)
    • 发送 signalsignal给孩子。

Note

在 Windows 上,SIGTERM 是terminate()的别名。可以将 CTRL_C_EVENT 和 CTRL_BREAK_EVENT 发送到以* creationflags *参数(包括 CREATE_NEW_PROCESS_GROUP)启动的进程。

2.6 版的新Function。

  • Popen. terminate ( )
    • 阻止孩子在 Posix OS 上,该方法将 SIGTERM 发送给子级。在 Windows 上,将调用 Win32 API 函数TerminateProcess()来停止子级。

2.6 版的新Function。

  • Popen. kill ( )
    • 杀死孩子。在 Posix OS 上,该Function将 SIGKILL 发送给子级。在 Windows 上,kill()terminate()的别名。

2.6 版的新Function。

以下属性也可用:

Warning

使用communicate()而不是.stdin.write.stdout.read.stderr.read来避免死锁,因为其他 OS 管道缓冲区中的任何一个都填满并阻塞了子进程。

  • Popen. stdin

    • 如果* stdin *参数为PIPE,则此属性是一个文件对象,为子进程提供 Importing。否则为None
  • Popen. stdout

    • 如果* stdout *参数为PIPE,则此属性是一个文件对象,提供子进程的输出。否则为None
  • Popen. stderr

    • 如果* stderr *参数是PIPE,则此属性是一个文件对象,提供子进程的错误输出。否则为None
  • Popen. pid

    • 子进程的进程 ID。

请注意,如果将* shell *参数设置为True,则这是生成的 shell 的进程 ID。

  • Popen. returncode

负值-N表示该子级已由 signalN终止(仅 Unix)。

17.1.3. Windows Popen 助手

STARTUPINFO类和以下常量仅在 Windows 上可用。

  • 类别 subprocess. STARTUPINFO

  • dwFlags

    • 一个位域,确定在进程创建窗口时是否使用某些STARTUPINFO属性。
si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
  • hStdInput

  • hStdOutput

    • 如果dwFlags指定STARTF_USESTDHANDLES,则此属性是该过程的标准输出句柄。否则,将忽略此属性,标准输出的默认值是控制台窗口的缓冲区。
  • hStdError

    • 如果dwFlags指定STARTF_USESTDHANDLES,则此属性是该过程的标准错误句柄。否则,将忽略此属性,并且标准错误的默认值是控制台窗口的缓冲区。
  • wShowWindow

为此属性提供了SW_HIDE。在passshell=True调用Popen时使用。

17.1.3.1. Constants

subprocess模块公开以下常量。

  • subprocess. STD_INPUT_HANDLE

    • 标准 Importing 设备。最初,这是控制台 Importing 缓冲区CONIN$
  • subprocess. STD_OUTPUT_HANDLE

    • 标准输出设备。最初,这是活动的控制台屏幕缓冲区CONOUT$
  • subprocess. STD_ERROR_HANDLE

    • 标准错误设备。最初,这是活动的控制台屏幕缓冲区CONOUT$
  • subprocess. SW_HIDE

    • 隐藏窗口。另一个窗口将被激活。
  • subprocess. STARTF_USESTDHANDLES

  • subprocess. STARTF_USESHOWWINDOW

  • subprocess. CREATE_NEW_CONSOLE

    • 新进程具有一个新的控制台,而不是继承其父级的控制台(默认)。

当使用shell=True创建Popen时,始终设置此标志。

  • subprocess. CREATE_NEW_PROCESS_GROUP
    • Popen creationflags参数,用于指定将创建一个新的过程组。对于在子进程上使用os.kill(),此标志是必需的。

如果指定了CREATE_NEW_CONSOLE,则忽略此标志。

17.1.4. 用子流程模块替换旧Function

在本节中,“ a 变为 b”表示 b 可以替代 a。

Note

如果找不到执行的程序,则本节中的所有“ a”Function都会(或多或少)无声地失败。 “ b”替换项将引发OSError

此外,如果所请求的操作产生非零的返回码,则使用check_output()进行的替换将以CalledProcessError失败。输出仍然可用作引发的异常的output属性。

在以下示例中,我们假设相关Function已经从subprocess模块导入。

17.1.4.1. 替换/ bin/sh shell 反引号

output=`mycmd myarg`

becomes:

output = check_output(["mycmd", "myarg"])

17.1.4.2. 更换 Shell 管道

output=`dmesg | grep hda`

becomes:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

启动 p2 之后的 p1.stdout.close()调用很重要,如果 p2 在 p1 之前退出,则 p1 才能接收 SIGPIPE。

另外,对于受信任的 Importing,仍然可以直接使用 Shell 自身的管道支持:

output=`dmesg | grep hda`

becomes:

output=check_output("dmesg | grep hda", shell=True)

17.1.4.3. 替换 os.system()

status = os.system("mycmd" + " myarg")
# becomes
status = subprocess.call("mycmd" + " myarg", shell=True)

Notes:

  • 通常不需要pass Shell 调用程序。

一个更现实的示例如下所示:

try:
    retcode = call("mycmd" + " myarg", shell=True)
    if retcode < 0:
        print >>sys.stderr, "Child was terminated by signal", -retcode
    else:
        print >>sys.stderr, "Child returned", retcode
except OSError as e:
    print >>sys.stderr, "Execution failed:", e

17.1.4.4. 取代 os.spawn 系列

P_NOWAIT example:

pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
==>
pid = Popen(["/bin/mycmd", "myarg"]).pid

P_WAIT example:

retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
==>
retcode = call(["/bin/mycmd", "myarg"])

Vector example:

os.spawnvp(os.P_NOWAIT, path, args)
==>
Popen([path] + args[1:])

Environment example:

os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
==>
Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})

17.1.4.5. 替换 os.popen(),os.popen2(),os.popen3()

pipe = os.popen("cmd", 'r', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
pipe = os.popen("cmd", 'w', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin
(child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize)
==>
p = Popen("cmd", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
(child_stdin,
 child_stdout,
 child_stderr) = os.popen3("cmd", mode, bufsize)
==>
p = Popen("cmd", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin,
 child_stdout,
 child_stderr) = (p.stdin, p.stdout, p.stderr)
(child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode,
                                                   bufsize)
==>
p = Popen("cmd", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)

在 Unix 上,os.popen2,os.popen3 和 os.popen4 也接受序列作为要执行的命令,在这种情况下,参数将直接传递给程序,而无需 shell 干预。可以按以下方式替换此用法:

(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode,
                                        bufsize)
==>
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)

返回码处理翻译如下:

pipe = os.popen("cmd", 'w')
...
rc = pipe.close()
if rc is not None and rc >> 8:
    print "There were some errors"
==>
process = Popen("cmd", shell=True, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
    print "There were some errors"

17.1.4.6. 替换 popen2 模块中的Function

(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
==>
p = Popen("somestring", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

在 Unix 上,popen2 还接受一个序列作为要执行的命令,在这种情况下,参数将直接传递给程序,而无需 shell 干预。可以按以下方式替换此用法:

(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize,
                                            mode)
==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

popen2.Popen3popen2.Popen4基本上与subprocess.Popen相同,除了:

  • 如果执行失败,Popen会引发异常。

    • capturestderr 参数替换为 stderr *参数。
  • 必须指定stdin=PIPEstdout=PIPE

  • popen2 默认情况下关闭所有文件 Descriptors,但是您必须使用Popen指定close_fds=True

17.1.5. Notes

17.1.5.1. 在 Windows 上将参数序列转换为字符串

在 Windows 上,* args *序列被转换为可以使用以下规则(与 MS C 运行时所使用的规则相对应)进行解析的字符串:

  • 参数由空格分隔,空格可以是空格或制表符。

  • 用双引号引起来的字符串被解释为单个参数,而不管其中包含的空格如何。带引号的字符串可以嵌入参数中。

  • 在双引号之前加反斜杠的解释为字面量双引号。

  • 反斜杠将按字面意义进行解释,除非它们紧接在双引号之前。

  • 如果反斜杠紧接在双引号之前,则每对反斜杠都将被解释为 Literals 反斜杠。如果反斜杠的数量为奇数,则最后一个反斜杠将按照规则 3 中的说明转义下一个双引号。