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

Вызов rsync из python subprocess.call

Я пытаюсь выполнить rsync через ssh из подпроцесса в python script, чтобы скопировать изображения с одного сервера на другой. У меня есть функция, определенная как:

def rsyncBookContent(bookIds, serverEnv):
    bookPaths = ""
    if len(bookIds) > 1:
        bookPaths = "{" + ",".join(("book_"+str(x)) for x in bookIds) + "}"
    else:
        bookPaths = "book_" + str(bookIds[0])

    for host in serverEnv['content.hosts']:
        args = ["rsync", "-avz", "--include='*/'", "--include='*.jpg'", "--exclude='*'", "-e", "ssh", options.bookDestDir + "/" + bookPaths, "[email protected]" + host + ":/home/jill/web/public/static/"]
        print "executing " + ' '.join(args)
        subprocess.call(args)

В конечном итоге я пытаюсь выполнить Python (что работает из оболочки bash):

rsync -avz --include='*/' --include='*.jpg' --exclude='*' -e ssh /shared/books/{book_482,book_347} [email protected]:/home/jill/web/public/static/

И действительно, моя заявка на печать выводит:

executing rsync -avz --include='*/' --include='*.jpg' --exclude='*' -e ssh /shared/books/{book_482,book_347} [email protected]:/home/jill/web/public/static/

Но при выполнении из этого python script возникают две проблемы:

  • Если len (bookIds) > 1, список подкаталогов под/shared/books/каким-то образом неверно истолкован bash или rsync. Сообщение об ошибке:
    • rsync: link_stat "/shared/books/{book_482, book_347}" не удалось: нет такого файла или каталога (2))
  • Если len (bookIds) == 1, все файлы под исходным каталогом rsynced (а не только *.jpg, как и мои намерения)

Кажется, что функция subprocess.call требует, чтобы некоторые символы были экранированы или что-то еще, no?

4b9b3361

Ответ 1

Выяснил мои проблемы. Мои проблемы были результатом моего непонимания того, как выполняется функция subprocess.call, и bash расширение списков внутри фигурных скобок.

Когда я выдавал команду rsync в оболочке bash с подкаталогами в фигурных скобках, bash действительно расширял это на несколько аргументов, которые передавались в rsync (/shared/books/book_1 shared/books/book_2, и т.д.). При передаче одной и той же строки с фигурными фигурными скобками "/shared/books/{book_1, book_2}" в функцию subprocess.call расширение не происходило, поскольку оно не проходило через bash, поэтому мой аргумент rsync был действительно "/shared/books/{book_1, book_2}".

Аналогично, одиночные кавычки вокруг шаблонов файлов ('*', '*.jpg' и т.д.) работают в командной строке bash (только значения внутри одинарных кавычек передаются в rsync), но внутри subprocess.call, одиночные кавычки передаются в rsync как шаблон файла ( "'*.jpg'" ).

Новый (рабочий) код выглядит следующим образом:

def rsyncBookContent(bookIds, serverEnv):
    bookPaths = []
    for b in bookIds:
        bookPaths.append(options.bookDestDir + "/book_" + str(b))
    args = []
    for host in serverEnv['content.hosts']:
        # copy all *.jpg files via ssh
        args = ["rsync", "-avz", "--include", "*/", "--include", "*.jpg", "--exclude", "*", "-e", "ssh"]
        args.extend(bookPaths)
        args.append("[email protected]" + host + ":/home/jill/web/public/static/"])
        print "executing " + ' '.join(args)
        subprocess.call(args)