【问题标题】:subprocess.call using string vs using listsubprocess.call 使用字符串与使用列表
【发布时间】:2013-02-13 02:48:19
【问题描述】:

我正在尝试将 rsync 与 subprocess.call 一起使用。奇怪的是,如果我传递 subprocess.call 一个字符串,它就可以工作,但它不适用于列表(ala,Python's doc)。

用字符串调用 sp.call:

In [23]: sp.call("rsync -av content/ writings_raw/", shell=True)
sending incremental file list

sent 6236 bytes  received 22 bytes  12516.00 bytes/sec
total size is 324710  speedup is 51.89
Out[23]: 0

用列表调用 sp.call:

In [24]: sp.call(["rsync", "-av", "content/", "writings_raw/"], shell=True)
rsync  version 3.0.9  protocol version 30
Copyright (C) 1996-2011 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 32-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.

rsync is a file transfer program capable of efficient remote update
via a fast differencing algorithm.

Usage: rsync [OPTION]... SRC [SRC]... DEST
  or   rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST
  or   rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
  or   rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST
  or   rsync [OPTION]... [USER@]HOST:SRC [DEST]
  or   rsync [OPTION]... [USER@]HOST::SRC [DEST]
  or   rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
The ':' usages connect via remote shell, while '::' & 'rsync://' usages connect
to an rsync daemon, and require SRC or DEST to start with a module name.

Options
 -v, --verbose               increase verbosity
 -q, --quiet                 suppress non-error messages
     --no-motd               suppress daemon-mode MOTD (see manpage caveat)
... snipped....
                             repeated: --filter='- .rsync-filter'
     --exclude=PATTERN       exclude files matching PATTERN
     --blocking-io           use blocking I/O for the remote shell
 -4, --ipv4                  prefer IPv4
 -6, --ipv6                  prefer IPv6
     --version               print version number
(-h) --help                  show this help (-h is --help only if used alone)
...snipped ...
rsync error: syntax or usage error (code 1) at main.c(1438) [client=3.0.9]
Out[24]: 1

我使用列表的方式有什么问题?你会如何解决它?我需要这个列表,因为我想使用变量。我当然可以使用:

  sp.call("rsync -av "+Orig+" "+Dest, shell=True)    

但我想了解subprocess 如何理解列表和字符串。

设置 shell=False 和一个列表:

In [36]: sp.call(['rsync', '-av', ORIG, DEST], shell=False)
sending incremental file list

sent 6253 bytes  received 23 bytes  12552.00 bytes/sec
total size is 324710  speedup is 51.74
Out[36]: 0

设置 shell=False 和一个字符串

In [38]: sp.call("rsync -av"+" "+ORIG+" "+DEST, shell=False)
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-38-0d366d3ef8ce> in <module>()
----> 1 sp.call("rsync -av"+" "+ORIG+" "+DEST, shell=False)

/usr/lib/python2.7/subprocess.pyc in call(*popenargs, **kwargs)
    491     retcode = call(["ls", "-l"])
    492     """
--> 493     return Popen(*popenargs, **kwargs).wait()
    494 
    495 

/usr/lib/python2.7/subprocess.pyc in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
    677                             p2cread, p2cwrite,
    678                             c2pread, c2pwrite,
--> 679                             errread, errwrite)
    680 
    681         if mswindows:

/usr/lib/python2.7/subprocess.pyc in _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
   1257                     if fd is not None:
   1258                         os.close(fd)
-> 1259                 raise child_exception
   1260 
   1261 

OSError: [Errno 2] No such file or directory

【问题讨论】:

  • 设置shell=False 时行为是否会改变(如果没有明确要求True,您通常应该这样做)?
  • @Jan-PhilipGehrcke,是的,它改变了。但这让我更加困惑......因为 shell=False 和 string 它完全相反。那么这里发生了什么?
  • 这很容易。 shell 想要一个字符串,所以给它一个。如果不使用 shell,则使用系统调用 family exec*(),它希望拆分参数 - 所以给它一个列表。

标签: python subprocess


【解决方案1】:

subprocess处理命令参数的规则其实有点复杂。

来自the docs

args 应该是程序参数序列或单个字符串。默认情况下,如果args 是一个序列,则要执行的程序是args 中的第一项。如果args 是一个字符串,则解释是平台相关 并在下面描述。请参阅 shellexecutable 参数以了解与默认行为的其他差异。 除非另有说明,否则建议将args 作为序列传递....如果shell 为True,则建议将args 作为字符串而不是序列传递。

shell=False:

在 Unix 上,如果 args 是一个字符串,则该字符串被解释为要执行的程序的名称或路径。但是,这只能在不向程序传递参数的情况下完成。

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

shell=True:

在带有shell=True 的Unix 上,shell 默认为/bin/sh。如果args 是字符串,则该字符串指定要通过shell 执行的命令。这意味着字符串的格式必须与在 shell 提示符下键入时的格式完全相同。这包括,例如,引用或反斜杠转义文件名,其中包含空格。 如果 args 是一个序列,则第一项指定命令字符串,任何附加项都将被视为 shell 本身的附加参数。

在带有shell=True 的 Windows 上,COMSPEC 环境变量指定默认 shell。唯一需要在 Windows 上指定 shell=True 的情况是当您希望执行的命令内置到 shell 中时(例如 dircopy)。您不需要shell=True 来运行批处理文件或基于控制台的可执行文件。

(所有重点都是我的)

【讨论】:

  • 不“强制”推荐。它是代码中的错误还是文档错误。你碰巧知道是哪个吗?快速查看源代码,并不明显
  • 推荐的意思是“为了最不令人惊讶的结果”。你可以做不推荐的事情——代码不会阻止你——结果将在我引用的 sn-ps 中记录。
  • 对我来说,使用 shell=True 并传递列表而不是字符串看起来完全损坏了,除非列表只有一个元素(即没有参数)。
  • @Davide,它根本没有损坏——该列表被附加到 ['sh', '-c'] 的参数列表中,它将第一个元素解析为要运行的代码,并将后面的元素解析为该代码的参数所有($1$2 等)。它的工作方式与文档中的工作方式完全相同。
  • 这太不切实际了,如果 Python 在这种情况下发出警告甚至抛出错误,我根本不会介意。如果您真的想将参数传递给 shell,请使用 sh -c 'rsync "$@"' _ "-av" "content/" "writings_raw/" 或类似名称明确地进行。
猜你喜欢
  • 2016-10-31
  • 2013-05-03
  • 2014-08-30
  • 1970-01-01
  • 2017-05-10
  • 2014-10-04
  • 2016-04-06
  • 1970-01-01
  • 2022-11-19
相关资源
最近更新 更多