使用SFTP递归删除目录

8

我使用SFTP服务器备份数据库和整个网站结构。由于使用了糟糕的脚本,导致在SFTP服务器上出现了重复文件。我尝试使用rmdir文件夹命令删除这些文件,但是却遇到了错误。

Couldn't remove directory: Failure

如果我理解正确,在SFTP中只有当文件夹为空时才能删除该文件夹。如果我使用代码rm folder/*,则不会删除内部文件夹。

那么我有没有其他方法可以做到这一点呢?


我用Filezilla来做这件事。 - tshepang
我只能从托管VPS服务器连接到它。 - itdxer
3个回答

16

你也可以使用以下方法挂载远程目录:

sshfs user@yourdomain.com:/path/to/remote local/path

那么只需使用 cd local/path 命令,然后您就可以自由地使用rm -r folder命令。


9

itdxer的解决方案非常好,但它并不会删除所有内容:如果子文件夹原本不为空,它只会删除子文件夹的内容。同时,也可以通过结合isdir和rm来缩短代码。

def rm(path):
    files = sftp.listdir(path)

    for f in files:
        filepath = os.path.join(path, f)
        try:
            sftp.remove(filepath)
        except IOError:
            rm(filepath)

    sftp.rmdir(path)

2
这是一个很好的答案。唯一的缺点是 os.path.join() 可能无法在跨系统时生成正确的路径。在 Windows 上运行此脚本并针对 Linux 服务器,会生成诸如 /tmp/dev\\afile.txt 的路径,导致脚本崩溃。最终我使用了 '/'.join(...),虽然不是普遍正确的方法,但在目标系统为 Linux 时可以使用。 - WoJ
为什么要在这里使用try/except呢?明确检查它是文件还是目录不是更好吗?如果有很多目录,需要捕获很多异常,这不会影响性能吗? - Andrius
@Andrius,有点晚了,但这是你问题的答案。在Python中,通常“宁愿请求原谅,也不要征得许可”(EAFP)更好。与网络I/O等真正的瓶颈相比,与异常相关的性能通常并不重要。换句话说,“过早优化实际上是一切罪恶的根源”。 - Mikhail Gerasimov
@MikhailGerasimov,是的,我知道Python推荐EAFP。虽然我使用这个经验法则。如果我预计大多数调用都会通过,我就捕获异常。但如果我知道很多时候可能会出现异常,那么我会检查它,而不是捕获它。例如,如果有50%的情况下预计会发生异常,我会使用简单的检查。如果大多数情况下异常将会发生,而不是通过,是否仍建议使用try/except? - Andrius
2
@Andrius 考虑以下参数:如果我们使用 not is_dir() 然后 remove(),我们将向远程 SFTP 发送两个请求,而不是在成功删除时发送单个请求(如果它是一个目录,我们对两种方法都有相同数量的请求)。更重要的是,EAFP 方法允许我们原子地删除文件:没有第三方会在我们执行 is_dir()remove() 之间更改任何内容。我们应该在每种具体情况下务实,但在这种情况下,仅出于上述原因,我个人更喜欢 EAFP。 - Mikhail Gerasimov
显示剩余2条评论

8

在Python中实现简单的解决方案。我认为这将有助于未来的工作。

import os
import paramiko
from stat import S_ISDIR

server ="any.sftpserver"
username = "uname"
password = "***"
path_to_hosts_file = os.path.join("~", ".ssh", "known_hosts")

ssh = paramiko.SSHClient()
ssh.load_host_keys(os.path.expanduser(path_to_hosts_file))
ssh.connect(server, username=username, password=password)

def isdir(path):
    try:
        return S_ISDIR(sftp.stat(path).st_mode)
    except IOError:
        return False

def rm(path):
    files = sftp.listdir(path=path)

    for f in files:
        filepath = os.path.join(path, f)
        if isdir(filepath):
            rm(filepath)
        else:
            sftp.remove(filepath)

    sftp.rmdir(path)

if __name__ == "__main__":
    rm("/path/to/some/directory/to/remove")

7
最糟糕的示例代码...试图从sftp服务器中删除“ /”目录。即使是最缺乏知识的人也可能会将此示例用作模板,并从“ /”目录中永久删除其FTP服务器上的数据 :) - Abhishek Kulkarni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接