如何修改此rsync命令以查找带有';的目录';用Python?

如何修改此rsync命令以查找带有';的目录';用Python?,python,rsync,python-2.6,Python,Rsync,Python 2.6,我在python中使用rsync命令,如下所示: rsync_out = subprocess.Popen(['sshpass', '-p', password, 'rsync', '--recursive', source], stdout=subprocess.PIPE) command = subprocess.Popen(('grep', '\.'), stdin=rsync_out.stdout, stdout=subproc

我在python中使用rsync命令,如下所示:

rsync_out = subprocess.Popen(['sshpass', '-p', password, 'rsync', '--recursive', source], 
                     stdout=subprocess.PIPE)
        command = subprocess.Popen(('grep', '\.'), stdin=rsync_out.stdout, stdout=subprocess.PIPE).communicate()[0]
rathi/20090209.02s1.2_sequence.txt

rathi/20090729.02s4.2_sequence.txt.gz

rathi/Homo_sapiens_UCSC_hg19.tar.gz

    rathi/hello/ok.txt
rathi/hello.v1/ok.txt
drwxr-xr-x        4096 2013/06/14 17:19:13 tmp/t
-rwxrwxr-x       14532 2013/06/14 17:17:23 tmp/t/a.out
-rwxrwxr-x       14539 2013/06/14 17:19:13 tmp/t/static-order
使用grep显示文件的目的如下:

rsync_out = subprocess.Popen(['sshpass', '-p', password, 'rsync', '--recursive', source], 
                     stdout=subprocess.PIPE)
        command = subprocess.Popen(('grep', '\.'), stdin=rsync_out.stdout, stdout=subprocess.PIPE).communicate()[0]
rathi/20090209.02s1.2_sequence.txt

rathi/20090729.02s4.2_sequence.txt.gz

rathi/Homo_sapiens_UCSC_hg19.tar.gz

    rathi/hello/ok.txt
rathi/hello.v1/ok.txt
drwxr-xr-x        4096 2013/06/14 17:19:13 tmp/t
-rwxrwxr-x       14532 2013/06/14 17:17:23 tmp/t/a.out
-rwxrwxr-x       14539 2013/06/14 17:19:13 tmp/t/static-order
而不是

rathi

rathi/20090209.02s1.2_sequence.txt

rathi/20090729.02s4.2_sequence.txt.gz

rathi/Homo_sapiens_UCSC_hg19.tar.gz

hello

rathi/hello/ok.txt
它可以正常工作,除非目录名上有

如果有一个名为hello.v1的目录,则输出为:

rathi/hello.v1
rathi/hello.v1/ok.txt
因为hello.v1是一个目录名,所以我只想这样显示:

rsync_out = subprocess.Popen(['sshpass', '-p', password, 'rsync', '--recursive', source], 
                     stdout=subprocess.PIPE)
        command = subprocess.Popen(('grep', '\.'), stdin=rsync_out.stdout, stdout=subprocess.PIPE).communicate()[0]
rathi/20090209.02s1.2_sequence.txt

rathi/20090729.02s4.2_sequence.txt.gz

rathi/Homo_sapiens_UCSC_hg19.tar.gz

    rathi/hello/ok.txt
rathi/hello.v1/ok.txt
drwxr-xr-x        4096 2013/06/14 17:19:13 tmp/t
-rwxrwxr-x       14532 2013/06/14 17:17:23 tmp/t/a.out
-rwxrwxr-x       14539 2013/06/14 17:19:13 tmp/t/static-order

我怎么能做到这一点呢?

就我个人而言,我不想麻烦使用
grep
,我只想使用Python自己的字符串过滤——然而,这不是你问的问题

由于文件名是远程的,Python只将其视为字符串,因此我们不能使用Python自己的任何文件操作例程(例如,
os.path.isdir()
)。因此,我认为有三种基本方法:

  • 用斜杠分割每个字符串,并使用它在内存中构建您自己的文件系统树表示。然后,遍历树,只显示叶节点(即文件)

  • 如果您可以假设目录中的文件总是紧跟在该目录之后列出,那么您可以对前面的条目进行快速检查,以查看该条目是否是这些目录之一中的文件

  • 使用
    rsync
    中的元信息

  • 我建议第三种选择。根据我对
    rsync
    的经验,它通常会提供如下完整的文件信息:

    rsync_out = subprocess.Popen(['sshpass', '-p', password, 'rsync', '--recursive', source], 
                         stdout=subprocess.PIPE)
            command = subprocess.Popen(('grep', '\.'), stdin=rsync_out.stdout, stdout=subprocess.PIPE).communicate()[0]
    
    rathi/20090209.02s1.2_sequence.txt
    
    rathi/20090729.02s4.2_sequence.txt.gz
    
    rathi/Homo_sapiens_UCSC_hg19.tar.gz
    
        rathi/hello/ok.txt
    
    rathi/hello.v1/ok.txt
    
    drwxr-xr-x        4096 2013/06/14 17:19:13 tmp/t
    -rwxrwxr-x       14532 2013/06/14 17:17:23 tmp/t/a.out
    -rwxrwxr-x       14539 2013/06/14 17:19:13 tmp/t/static-order
    
    在您的示例中,我看不到任何删除此附加信息的代码,您可以通过查找以
    d
    而不是
    -
    开头的任何行,轻松使用此代码筛选出目录

    如果您没有此扩展信息,则需要执行另外两个操作之一。第一个选项非常简单——只需按斜杠拆分,然后向下移动一个标准树结构,为尚未看到的目录和文件添加条目。解析完所有条目后,就可以遍历树并打印出没有子节点的任何节点

    第二个选项更复杂,但内存效率更高,您可以维护父目录列表,并检查它们是否是列表中当前项的前缀。如果是这样,您可以确保前一个是目录,当前一个是文件,因此您可以将前一个标记为不显示的内容。如果
    rsync
    以可预测的顺序返回项目,则在递归“退出”该目录后,也可以将项目从该列表中删除。您必须确保只检查斜杠边界处的前缀(因此
    foo/dir
    不是
    foo/dir bar
    的父项,而是
    foo/dir/bar
    的父项)。一般来说,这种方法相当复杂,除非您处理的是非常大的目录树,否则其他方法之一可能更可取

    顺便说一下,这两种纯基于字符串的方法都有一个缺点,即空目录与文件无法区分,因为只有目录中是否存在文件才能区分它们。这是我建议使用
    rsync
    中的元信息的另一个原因

    编辑

    根据要求,使用
    rsync
    元数据的示例如下:

    import subprocess
    
    cmdline = ["rsync", "-e", "ssh", "-r", "user@host:/dir"]
    proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
    for entry in proc.stdout:
        items = entry.strip().split(None, 4)
        if not items[0].startswith("d") and "." in items[4]:
            print items[4]
    
    在本例中,我直接调用
    rsync
    ,并让它使用
    ssh
    ,假设设置了适当的ssh密钥。我强烈建议使用SSH密钥而不是
    sshpass
    实用程序-从安全角度来看,以明文形式存储密码是一个非常糟糕的主意。如果你不担心钥匙被盗,你可以设置钥匙,但不需要密码。有很多页面解释如何创建SSH密钥(例如)

    user
    host
    /dir
    替换为远程计算机上的用户名、远程计算机的主机名和要在远程计算机上列出的父目录(如果要列出用户的主目录,可以省略
    /dir
    )。否则,代码将不经修改地运行。If将打印它找到的每个文件的路径名,跳过不包含点的目录和项目。如果您的点过滤器也只是试图跳过目录,则可以在项目[4]中省略“和”。”

    编辑2

    本例仅打印条目,但当然您可能需要执行其他操作。如果你真的想变得聪明,你可以把它写成一个生成器,在项目出现时调用
    yield
    。我在下面有一个例子,它也会打印项目,但是你可以看到它是如何被用来做其他事情的。我还添加了一些更好的错误处理,以确保
    子流程的使用不会死锁:

    编辑3:我已经更新了这个示例,包括文件大小和修改时间。这是基于我从
    rsync
    中得到的信息-如果您的格式不同,您可能需要使用
    items
    中的不同成员,或者可能将格式字符串更改为
    strptime()
    ,以匹配
    rsync
    返回的格式


    您应该能够将整个
    find_remote_files()
    函数粘贴到您的代码中,并直接使用它,如果您愿意的话。

    谢谢您的精彩回答。我更喜欢第三种方法。你能给我举个例子吗。谢谢我在我的帖子中添加了几个例子,希望能回答你的问题。我建议使用第二个函数中的生成器函数,希望示例能够清楚地说明如何使用它。这一个比第一个稍微复杂一点,但它处理一些罕见的终止情况,如果
    rsync
    发生错误,在第一个示例中可能会导致死锁。感谢您的精彩回答,但我想知道大小和