subprocess.call с използване на низ срещу използване на списък

Опитвам се да използвам rsync с subprocess.call. Странно, работи, ако предам subprocess.call низ, но няма да работи със списък (ала, документът на Python).

извикване на 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

person oz123    schedule 27.02.2013    source източник
comment
Променя ли се поведението, когато зададете shell=False (което обикновено трябва да направите, ако True не се изисква изрично)?   -  person Dr. Jan-Philip Gehrcke    schedule 27.02.2013
comment
@Jan-PhilipGehrcke, Да, променя се. Но това ме прави още по-объркан... защото с shell=False и string е точно обратното. И така, какво става тук?   -  person oz123    schedule 27.02.2013
comment
Лесно е. Обвивката иска низ, така че му дайте. Ако не използвате обвивката, се използва семейството на системните повиквания exec*(), което иска параметрите да бъдат разделени - така че дайте списък.   -  person glglgl    schedule 27.02.2013
comment


Отговори (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, за да стартирате пакетен файл или изпълним файл, базиран на конзолата.

(всички акценти са мои)

person nneonneo    schedule 27.02.2013
comment
Препоръчително не е задължително. Дали това е или грешка в кода, или грешка в документацията. Случайно да знаете кое? От бърз поглед на изходния код не е очевидно - person Davide; 01.03.2016
comment
Препоръчителни средства за най-малко изненадващ резултат. Можете да направите нещото, което не се препоръчва - кодът няма да ви спре - и резултатите ще бъдат както са документирани в цитираните от мен фрагменти. - person nneonneo; 01.03.2016
comment
За мен използването на shell=True и предаване на списък вместо низ изглежда напълно счупено, освен ако списъкът има само един елемент (т.е. без аргументи). - person Davide; 02.03.2016
comment
@Davide, изобщо не е повреден -- списъкът е добавен към списъка с аргументи на ['sh', '-c'], който анализира първия елемент като код за изпълнение, а по-късните елементи изобщо като аргументи към този код ($1, $2 и т.н.). Работи точно както е документирано да работи. - person Charles Duffy; 18.01.2020
comment
Това е достатъчно кичозно, че няма да имам нищо против, ако Python предупреди или дори изведе грешка в този сценарий. Ако наистина искате да предадете аргументи на обвивката, направете го изрично с sh -c 'rsync "$@"' _ "-av" "content/" "writings_raw/" или подобен. - person tripleee; 29.01.2020