2013-01-11 12 views
12

Ich versuche rsync über ssh aus einem Subprozess in einem Python-Skript auszuführen, um Bilder von einem Server auf einen anderen zu kopieren. Ich habe eine Funktion wie folgt definiert:rsync aus Python aufrufen subprocess.call

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) 

Was ich versuche letztlich zu tun haben Python dies (die von einer Bash-Shell arbeitet) ausführen:

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

Und in der Tat meine print-Anweisung gibt:

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

Aber wenn aus diesem python-Skript ausgeführt wird, gibt es zwei Probleme:

  1. Wenn len (bookIds)> 1, wird die Liste der Unterverzeichnisse unter/shared/books/irgendwie von bash oder rsync falsch interpretiert. Die Fehlermeldung lautet:
    • rsync: link_stat "/ shared/Bücher/{book_482, book_347}" fehlgeschlagen: Keine solche Datei oder ein Verzeichnis (2))
  2. wenn len (bookIds) == 1, alle Dateien im Quellverzeichnis sind rsynced (nicht nur * .jpg, wie meine Absicht ist)

scheint, als ob die subprocess.call Funktion einige Zeichen erfordert entkommen oder etwas zu, nicht wahr?

+0

Aus Neugier, was passiert, wenn man 'shell = true' in Ihrem Anruf eingestellt? Zum Beispiel, 'subprocess.call (args, shell = True)' – sberry

Antwort

17

Ermittelt meine Probleme. Meine Probleme waren das Ergebnis meines Missverständnisses, wie die Funktion subprocess.call ausgeführt wird, und der Erweiterung von Listen durch bash in geschweiften Klammern.

Als ich den Befehl rsync in einer Bash-Shell mit Unterverzeichnissen in geschweiften Klammern ausgab, erweiterte bash diese in mehrere Argumente, die an rsync übergeben wurden (/ shared/books/book_1 shared/books/book_2 usw.)). Wenn die gleiche Zeichenfolge mit geschweiften Klammern "/ shared/books/{book_1, book_2}" an die Funktion subprocess.call übergeben wurde, fand die Erweiterung nicht statt, da sie nicht durch bash ging, also war mein Argument für rsync wirklich "/ shared/books/{Buch_1, Buch_2}". Die einzelnen Anführungszeichen um die Dateimuster ('*', '* .jpg' usw.) funktionieren ebenfalls in der Bash-Befehlszeile (nur die Werte in den einfachen Anführungszeichen werden an rsync übergeben), aber innerhalb des Unterprozesses .call, die einfachen Anführungszeichen werden an rsync als Dateimuster übergeben ("'* .jpg'").

Neu (in Betrieb) Code sieht wie folgt aus:

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)