15

Pythonスクリプトのサブプロセスからssh経由でrsyncを実行して、あるサーバーから別のサーバーにイメージをコピーしようとしています。次のように定義された関数があります。

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, "jill@" + 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} jill@10.12.27.20:/home/jill/web/public/static/

そして実際、私のprintステートメントの出力は次のとおりです。

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

しかし、この python スクリプト内から実行すると、2 つの問題があります。

  1. len(bookIds) > 1 の場合、/shared/books/ の下のサブディレクトリのリストが bash または rsync によって何らかの形で誤って解釈されます。エラーメッセージは次のとおりです。
    • rsync: link_stat "/shared/books/{book_482,book_347}" が失敗しました: そのようなファイルまたはディレクトリはありません (2))
  2. len(bookIds) == 1 の場合、ソース ディレクトリにあるすべてのファイルが再同期されます (*.jpg だけでなく、意図したとおりです)。

subprocess.call 関数では、一部の文字をエスケープする必要があるかのようです。

4

1 に答える 1

21

私の問題を理解しました。私の問題は、subprocess.call関数がどのように実行されるかについての誤解と、中括弧内のリストのbashによる拡張の結果でした。

中括弧で囲まれたサブディレクトリを使用してbashシェルでrsyncコマンドを発行していたとき、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内では、一重引用符はファイルパターン( "'* .jpg'")としてrsyncに渡されます。

新しい(動作する)コードは次のようになります。

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("jill@" + host + ":/home/jill/web/public/static/"])
        print "executing " + ' '.join(args)
        subprocess.call(args)
于 2013-01-11T16:50:17.260 に答える