Подтвердить что ты не робот

Subprocess.call с использованием строки vs с использованием списка

Я пытаюсь использовать rsync с subprocess.call. Как ни странно, он работает, если я передаю subprocess.call строку, но она не будет работать со списком (ala, Python 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]... [[email protected]]HOST:DEST
  or   rsync [OPTION]... SRC [SRC]... [[email protected]]HOST::DEST
  or   rsync [OPTION]... SRC [SRC]... rsync://[[email protected]]HOST[:PORT]/DEST
  or   rsync [OPTION]... [[email protected]]HOST:SRC [DEST]
  or   rsync [OPTION]... [[email protected]]HOST::SRC [DEST]
  or   rsync [OPTION]... rsync://[[email protected]]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)    

Но я хотел бы понять, как подпроцесс понимает списки против строк.

с установкой 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

должен = 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
4b9b3361

Ответ 1

subprocess правила для обработки аргумента команды на самом деле немного сложны.

От документы:

args должна быть последовательностью аргументов программы или одной строкой. По умолчанию исполняемая программа является первым элементом в args, если args является последовательностью. Если args - строка, интерпретация зависит от платформы и описывается ниже. См. Аргументы shell и executable для дополнительных отличий от поведения по умолчанию. Если не указано иное, рекомендуется передать args в качестве последовательности.... Если shell - True, рекомендуется передать args как строку, а не как последовательность.

С shell=False:

В Unix, если args - это строка, строка интерпретируется как имя или путь для исполняемой программы. Однако это можно сделать, если не передать аргументы программе.

В Windows, если args - это последовательность, она будет преобразована в строку способом, описанным в Преобразование последовательности аргументов в строку в Windows. Это связано с тем, что базовый CreateProcess() работает с строками.

С shell=True:

В Unix с shell=True оболочка по умолчанию имеет значение /bin/sh. Если args - строка, строка указывает команду для выполнения через оболочку. Это означает, что строка должна быть отформатирована точно так же, как и при вводе в командной строке. Это включает в себя, например, цитирование или обратную косую черту с экранированием имен файлов с пробелами в них. Если args - это последовательность, первый элемент указывает командную строку, и любые дополнительные элементы будут рассматриваться как дополнительные аргументы самой оболочки.

В Windows с shell=True переменная среды COMSPEC указывает оболочку по умолчанию. Единственный раз, когда вам нужно указать shell=True в Windows, - это когда команда, которую вы хотите выполнить, встроена в оболочку (например, dir или copy). Вам не нужно shell=True для запуска командного файла или исполняемого файла на основе консоли.

(все внимание мое)