2013-01-11 17 views
12

Sto provando ad eseguire rsync su ssh da un sottoprocesso in uno script python per copiare immagini da un server a un altro. Ho una funzione definita come:chiamare rsync da python 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) 

Quello che sto in ultima analisi, cercando di fare è di avere Python eseguire questo (che funziona da una shell bash):

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

E in effetti la mia uscite istruzione print:

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

Ma quando eseguito dall'interno di questo script python, ci sono due problemi:

  1. se len (bookIds)> 1, l'elenco delle sottodirectory in/shared/books/è in qualche modo erroneamente interpretato da bash o rsync. Il messaggio di errore è:
    • rsync: link_stat "/ shared/libri/{book_482, book_347}" non riuscita: Nessun file o directory (2))
  2. se len (bookIds) == 1, tutti file nella directory di origine vengono rsynced (non solo * .jpg, come è mia intenzione)

sembra come se la funzione subprocess.call richiede alcuni caratteri da sfuggiti o qualcosa del genere, no?

+0

Per curiosità, cosa succede se si imposta 'shell = true' nella chiamata? Ad esempio, 'subprocess.call (args, shell = True)' – sberry

risposta

17

Ho capito i miei problemi. I miei problemi erano il risultato del mio fraintendimento su come viene eseguita la funzione subprocess.call e l'espansione di bash delle liste all'interno di parentesi graffe.

Quando stavo emettendo il comando rsync in una shell bash con sottodirectory in parentesi graffe, bash stava davvero espandendola in più argomenti che venivano passati a rsync (/ shared/books/book_1 shared/books/book_2, etc.). Quando si passa la stessa stringa con parentesi graffe "/ shared/books/{book_1, book_2}" alla funzione subprocess.call, l'espansione non stava accadendo, dal momento che non stava passando per bash, quindi il mio argomento per rsync era davvero "/ shared/books/{book_1, book_2}".

Analogamente, le virgolette singole attorno ai modelli di file ('*', '* .jpg', ecc.) Funzionano sulla riga di comando bash (solo i valori all'interno delle virgolette singole vengono passati a rsync), ma all'interno del sottoprocesso .call, le virgolette singole vengono passate a rsync come pattern del file ("'* .jpg'").

Nuovo codice (di lavoro) si presenta così:

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)