17.1. subprocessSubprocess management

New in version 2.4.

subprocess 模块允许你产生新的进程,然后连接它们的输入/输出/错误管道,并获取返回值。本模块意在替换下面几个老的模块和函数:

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

Information about how this module can be used to replace the older functions can be found in the subprocess-replacements section.

See also

POSIX users (Linux, BSD, etc.) are strongly encouraged to install and use the much more recent subprocess32 module instead of the version included with python 2.7. It is a drop in replacement with better behavior in many situations.

PEP 324 – 提出 subprocess 模块的 PEP

17.1.1. Using the subprocess Module

启动一个子进程建议使用下面的便捷函数。当对于更高级的使用场景它们不能满足你的需求时,可以使用底层的Popen接口。

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

Run the command described by args. Wait for command to complete, then return the returncode attribute.

上面显示的只是最常用的参数,其它参数将在下面的经常用到的参数一节中描述(因此缩写的形式有点奇怪)。The full function signature is the same as that of the Popen constructor - this functions passes all supplied arguments directly through to that interface.

Examples:

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

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

Warning

Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Note

Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

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

Run command with arguments. Wait for command to complete. If the return code was zero then return, otherwise raise CalledProcessError. CalledProcessError对象将把返回码保存在returncode属性中。

上面显示的只是最常用的参数,其它参数将在下面的经常用到的参数中描述(因此参数缩写的形式有点奇怪)。The full function signature is the same as that of the Popen constructor - this functions passes all supplied arguments directly through to that interface.

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

New in version 2.5.

Warning

Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Note

Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

Run command with arguments and return its output as a byte string.

If the return code was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and any output in the output attribute.

上面显示的只是最常用的参数,其它参数将在下面的经常用到的参数中描述(因此参数缩写的形式有点奇怪)。The full function signature is largely the same as that of the Popen constructor, except that stdout is not permitted as it is used internally. All other supplied arguments are passed directly through to the Popen constructor.

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

To also capture standard error in the result, use 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'

New in version 2.7.

Warning

Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Note

Do not use stderr=PIPE with this function as that can deadlock based on the child process error volume. Use Popen with the communicate() method when you need a stderr pipe.

subprocess.PIPE

Special value that can be used as the stdin, stdout or stderr argument to Popen and indicates that a pipe to the standard stream should be opened.

subprocess.STDOUT

Special value that can be used as the stderr argument to Popen and indicates that standard error should go into the same handle as standard output.

exception subprocess.CalledProcessError

Exception raised when a process run by check_call() or check_output() returns a non-zero exit status.

returncode

Exit status of the child process.

cmd

Command that was used to spawn the child process.

output

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

17.1.1.1. Frequently Used Arguments

To support a wide variety of use cases, the Popen constructor (and the convenience functions) accept a large number of optional arguments. For most typical use cases, many of these arguments can be safely left at their default values. The arguments that are most commonly needed are:

args is required for all calls and should be a string, or a sequence of program arguments. 一般倾向于提供一个参数的序列,因为这可以让该模块来处理参数的转义和引用(例如允许文件名中包含空格)。如果传递一个单一的字符串,要么shell必须为True(参见下文),要么该字符串必须只是简单地指明要执行的程序的名字且不带任何参数。

stdin, stdout and stderr specify the executed program’s standard input, standard output and standard error file handles, respectively. 合法的值有PIPE、一个已经存在的文件描述符(一个正整数)、一个已经存在的文件对象和NonePIPE表示应该为子进程创建一个新的管道。如果为默认设置None,则不会发生重定向;子进程的文件句柄将从父进程中继承。另外,stderr 可以为STDOUT,它表示来自子进程中标准错误的数据应该被捕获到和标准输出相同的文件中。

stdout 或者stderr 为管道时且universal_newlinesTrue,那么所有的行结束符将被转换成'\n' ,正如open()universal newlines 'U' 模式参数所描述的一样。

如果shellTrue,那么指定的命令将通过shell执行。如果你使用Python作为主要的控制流并仍然想方便地访问shell功能,例如shell 管道、文件名通配符、环境变量的扩展以及~访问某个用户的home目录,那么这将非常有用。然而,请注意Python自身提供许多类似shell功能的实现(特别地,如glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser()shutil)。

警告

执行的shell命令如果来自不可信任的输入源将使得程序容易受到shell注入攻击,一个严重的安全缺陷可能导致执行任意的命令。因为这个原因,在命令字符串是从外部输入的情况下使用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的功能,所以不会受此漏洞影响;参见Popen构造函数文档中的注意事项以得到如何使shell=False工作的有用提示。

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

这些选项和其它所有选项在Popen构造函数的文档中有更详细的描述。

17.1.1.2. Popen 构造函数

该模块中进程的创建和管理底层是通过Popen类处理的。它提供许多灵活性以便开发人员能够处理便捷函数没有覆盖到的较少见到的情形。

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 是一个字符串,那么其解释将与平台有关,在下文有描述。其它与默认行为的区别,参见shellexecutable 参数。除非另外说明,建议传递一个序列给args

在Unix上,如果args 是一个字符串,该字符串将解释为要执行的程序的名字或路径。然而,这只能在不传递参数给程序时可行。

shlex.split()在决定args正确的分词时非常有用,特别是复杂的情形:

>>> 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!

Note in particular that options (such as -input) and arguments (such as eggs.txt) that are separated by whitespace in the shell go in separate list elements, while arguments that need quoting or backslash escaping when used in the shell (such as filenames containing spaces or the echo command shown above) are single list elements.

在Windows上,如果args是一个序列,它将以Converting an argument sequence to a string on Windows中描述的方式转换为一个字符串。这是因为底层的CreateProcess()需要在字符串上运作。

shell 参数(默认为False)指定是否使用shell来执行程序。如果shellTrue,则建议传递一个字符串而不是序列给args

在Unix上,如果shell=True,那么shell默认为/bin/sh. If args is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of:

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

On Windows with shell=True, the COMSPEC environment variable specifies the default shell. The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable.

Warning

Passing shell=True can be a security hazard if combined with untrusted input. See the warning under Frequently Used Arguments for details.

bufsize, if given, has the same meaning as the corresponding argument to the built-in open() function: 0 means unbuffered, 1 means line buffered, any other positive value means use a buffer of (approximately) that size. A negative bufsize means to use the system default, which usually means fully buffered. The default value for bufsize is 0 (unbuffered).

Note

If you experience performance issues, it is recommended that you try to enable buffering by setting bufsize to either -1 or a large enough positive value (such as 4096).

executable 参数指定一个要执行的替换程序。它很少用到。When shell=False, executable replaces the program to execute specified by args. However, the original args is still passed to the program. Most programs treat the program specified by args as the command name, which can then be different from the program actually executed. On Unix, the args name becomes the display name for the executable in utilities such as ps. 如果shell=True,在Unix上executable 参数表示指定一个替换默认/bin/sh的shell。

stdinstdoutstderr 分别指定要执行的程序的标准输入、标准输出和标准错误文件句柄。合法的值有PIPE、一个已经存在的文件描述符(一个正整数)、一个已经存在的文件对象和NonePIPE表示应该为子进程创建一个新的管道。 如果为默认设置None,则不会发生重定向; 子进程的文件句柄将从父进程中继承。 另外,stderr 可以为STDOUT,它表示来自子进程中标准错误的数据应该被捕获到和标准输出相同的文件中。

preexec_fn 如果设定为一个可调用对象,该对象将在子进程中在子进程执行之前调用。(只在Unix上)

close_fds 如果为真,所有的描述符除了012之外将在执行子进程之前关闭。(只在Unix上)。或者,在Windows上,close_fds 如果为真,那么子进程不会继承任何句柄。注意,在Windows上,你不可以设置close_fds 为真并同时通过设置stdinstdout 或者stderr重定向标准句柄 。

如果cwd不为None,那么子进程将在执行命令前将当前目录指向cwd注意在搜索可执行程序时,该目录不会考虑在内,所以你不可以指定相对cwd 的程序路径。

env 如果不为None,它必须是一个定义了新进程环境变量的映射;子进程不再从当前程序中集成环境变量,而是使用由env定义的环境变量。

注意

如果指定,env 必须提供要执行程序的任何变量。在Windows上,为了执行一个side-by-side assembly,指定的env 必须包含一个合法的SystemRoot

universal_newlines 如果为True,那么文件对象stdoutstderr 将被看做以universal newlines 模式打开的文本文件。不论每一行的终止符是Unix风格的'\n'、旧式Macintosh风格的'\r'或者是Windows风格的'\r\n'所有这些终止符都将被Python程序当做'\n'处理。

注意

该功能知道在Python构建时选择支持统一换行符(默认行为)时才可用。同时,文件对象stdoutstdinstderr 的换行符属性不会被communicate()方法更新。

startupinfo 如果给出,将是一个 STARTUPINFO对象,它将传递给底层的CreateProcess函数。creationflags如果给出, 可以是CREATE_NEW_CONSOLE或者 CREATE_NEW_PROCESS_GROUP(只在Windows上)

17.1.1.3. 异常

在新程序开始执行之前出现的异常将在父进程中被重新引发。另外,该异常对象将包含一个额外的属性叫做child_traceback,它是一个包含子进程回溯信息的字符串。

最常见的异常是OSError例如,当试图执行一个不存在的文件时会发生该异常。应用程序应该准备好捕获OSError异常。

如果Popen 的调用带有非法的参数将引发ValueError

如果调用的进程返回非零的返回码,check_call()check_output() 将引发CalledProcessError异常。

17.1.1.4. 安全性

与其它popen函数不同,这里的实现永远不会隐式调用系统的shell。这意味着所有的字符包括shell元字符,都可以安全地传递给子进程。明显地,如果现实调用shell,那么保证所有的空格和元字符被正确地引用应该是应用程序的责任。

17.1.2. Popen 对象

Instances of the Popen class have the following methods:

Popen.poll()

Check if child process has terminated. Set and return returncode attribute.

Popen.wait()

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

Warning

This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.

Popen.communicate(input=None)

与进程交互:将数据发送到标准输入。Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.

communicate() returns a tuple (stdoutdata, stderrdata).

Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other than None in the result tuple, you need to give stdout=PIPE and/or stderr=PIPE too.

Note

The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

Popen.send_signal(signal)

Sends the signal signal to the child.

Note

On Windows, SIGTERM is an alias for terminate(). CTRL_C_EVENT和CTRL_BREAK_EVENT可以发送给启动参数 包含creationflagsCREATE_NEW_PROCESS_GROUP 进程。

New in version 2.6.

Popen.terminate()

Stop the child. On Posix OSs the method sends SIGTERM to the child. On Windows the Win32 API function TerminateProcess() is called to stop the child.

New in version 2.6.

Popen.kill()

Kills the child. 在Posix操作系统上,该函数发送SIGKILL给子进程。On Windows kill() is an alias for terminate().

New in version 2.6.

The following attributes are also available:

警告

使用communicate()而不用.stdin.write.stdout.read 或者.stderr.read以避免由于其它操作系统管道缓存填满并阻塞子进程引起的死锁。

Popen.stdin

如果stdin 参数为PIPE,则该属性为一个文件对象,它提供子进程的输入。否则,为None

Popen.stdout

如果stdout 参数为PIPE,则该属性是一个文件对象,它提供子进程中的输出。否则,为None

Popen.stderr

如果stderr 参数为PIPE,则该属性是一个文件对象,它提供子进程中的错误输出。否则,为None

Popen.pid

子进程的进程ID。

注意如果你设置shell 参数为True,那么它是产生的shell的进程ID。

Popen.returncode

子进程的返回码,由poll()wait()设置(communicate()是间接设置)。None值表示子进程还没有终止。

一个负的值-N表示子进程被信号N终止(只在Unix上)。

17.1.3. Windows 上的 Popen 辅助工具

STARTUPINFO 类和下面的常量只在 Windows 上可以使用。

class subprocess.STARTUPINFO

部分支持Windows STARTUPINFO结构,用于Popen创建。.

dwFlags

一个位域,它决定在进程创建一个窗口时是否使用特定的STARTUPINFO属性。

si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
hStdInput

如果dwFlags指定STARTF_USESTDHANDLES,该属性为进程的标准输入句柄。 如果STARTF_USESTDHANDLES没有指定,默认的标准输入为键盘缓冲区。

hStdOutput

如果dwFlags指定STARTF_USESTDHANDLES,该属性为进程的标准输出句柄。否则,忽略该属性且默认的标准输出为控制台窗口的缓冲区。

hStdError

如果dwFlags指定STARTF_USESTDHANDLES,该属性为进程的标准错误输出句柄。 否则,忽略该属性且默认的标准错误输出为控制台窗口的缓冲区。

wShowWindow

如果dwFlags指定STARTF_USESHOWWINDOW,该属性可以是在ShowWindow 函数的nCmdShow参数中指定的任意值,SW_SHOWDEFAULT除外。否则,忽略该属性。

该属性提供了SW_HIDE它在以shell=True调用Popen时使用。

17.1.3.1. Constants

The subprocess module exposes the following constants.

subprocess.STD_INPUT_HANDLE

标准输入设备。它的初始值是控制台输入缓冲区,CONIN$

subprocess.STD_OUTPUT_HANDLE

标准输出设备。它的初始值是控制台屏幕缓冲区,CONOUT$

subprocess.STD_ERROR_HANDLE

标准错误设备。它的初始值是控制台屏幕缓冲区,CONOUT$

subprocess.SW_HIDE

隐藏窗口。另外一个窗口将被激活。

subprocess.STARTF_USESTDHANDLES

表示STARTUPINFO.hStdInputSTARTUPINFO.hStdOutputSTARTUPINFO.hStdError 属性包含额外的信息。

subprocess.STARTF_USESHOWWINDOW

表示STARTUPINFO.wShowWindow 属性包含额外的信息。

subprocess.CREATE_NEW_CONSOLE

新的进程将具有一个新的控制台,而不是继承它父进程的控制台(默认行为)。

当以shell=True创建Popen时,该标记位总是被设置。

subprocess.CREATE_NEW_PROCESS_GROUP

Popen的一个creationflags参数,用于表示将创建一个新的进程组。该标志在子进程上使用os.kill()时是必须的。

如果指定CREATE_NEW_CONSOLE,该标志将被忽略。

17.1.4. 使用 subprocess 模块替换旧的函数

在本小节中,“a 变成 b”的意思是b 可以作为a 的一种替换使用。

注意

本节中的所有函数“a”(或多或少)如果执行程序找不到都不会报错;而如果将其替换为“b”将引发OSError

另外,如果请求的操作产生一个非零的返回码,这些使用check_output()的替换方法将在失败时引发CalledProcessError其输出在引发异常的output属性中仍然能访问到。

在下面的例子中,我们假定相关的函数已经从subprocess模块导入。

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

output=`mycmd myarg`
# becomes
output = check_output(["mycmd", "myarg"])

17.1.4.2. Replacing shell pipeline

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信号。

另外一种方法,对于可信任的输入,也可以直接使用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)

注意:

  • 通常不需要通过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 示例:

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

P_WAIT 示例:

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

向量示例:

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

环境变量示例:

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", 'w', shell=True, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
    print "There were some errors"

17.1.4.6. 替换 popen2 模块中的函数

(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)

On Unix, popen2 also accepts a sequence as the command to execute, in which case arguments will be passed directly to the program without shell intervention. This usage can be replaced as follows:

(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.Popen3 and popen2.Popen4 basically work as subprocess.Popen, except that:

  • Popen raises an exception if the execution fails.
  • capturestderr 参数替换成stderr 参数。
  • 必须指定stdin=PIPEstdout=PIPE
  • popen2默认关闭所有文件描述符,但是使用Popen你必需指定close_fds=True

17.1.5. Notes

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

在 Windows 上,args 序列被转换为一个可以使用下面的规则(MS C 的运行时规则)解析的字符串:

  1. Arguments are delimited by white space, which is either a space or a tab.
  2. A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument.
  3. A double quotation mark preceded by a backslash is interpreted as a literal double quotation mark.
  4. Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
  5. If backslashes immediately precede a double quotation mark, every pair of backslashes is interpreted as a literal backslash. If the number of backslashes is odd, the last backslash escapes the next double quotation mark as described in rule 3.