【问题标题】:Is it possible to transfer files from a directory using SCP in Python but ignore hidden files or sym links?是否可以在 Python 中使用 SCP 从目录传输文件但忽略隐藏文件或符号链接?
【发布时间】:2021-12-22 06:12:46
【问题描述】:

我目前在 Python 中使用 Paramiko 和 SCPClient 将目录从一台服务器传输到另一台服务器作为备份方式。这很好用,但是我不希望它复制隐藏文件(.file_name)或符号链接。这可能吗?

不幸的是,rsync 对我来说不是一个选项,因为它在我连接的任何一个远程服务器上都不可用。我的脚本如下(敏感信息替换为虚拟数据)。请注意,我需要先连接到跳转主机,然后才能连接到 target_1 或 target_2。

import os
import shutil
import time
import paramiko
from scp import SCPClient

#set up ssh variables
j_host = '00.00.00.00'
target_host_1 = '00.00.00.001'
target_host_2 = '00.00.00.002'
port_no = 22
username = ''
passw = ''

#set up temporary folder on local machine to store files
path = "/local_path/"
os.mkdir(path)

#create SSH Client for jump server
jump_host=paramiko.SSHClient()
jump_host.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jump_host.connect(j_host, username=username, password=passw)

#set up channel to connect to 1 via jump server
jump_host_transport_1 = jump_host.get_transport()
src_addr = (j_host, port_no)
dest_addr_1 = (target_host_1, port_no)
jump_host_channel_1 = jump_host_transport_1.open_channel("direct-tcpip", dest_addr_1, src_addr)

#set up channel to connect to 2 via jump server
jump_host_transport_2 = jump_host.get_transport()
dest_addr_2 = (target_host_2, port_no)
jump_host_channel_2 = jump_host_transport_2.open_channel("direct-tcpip", dest_addr_2, src_addr)

#function which sets up target server, either 1 or 2
def create_SSHClient(server, port, user, password, sock):
    target=paramiko.SSHClient()
    target.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    target.connect(server, port, user, password, sock=sock)
    return target

#invoke above function to set up connections for 1 & 2
ssh_1 = create_SSHClient(target_host_1, port_no, username, passw, jump_host_channel_1)
ssh_2 = create_SSHClient(target_host_2, port_no, username, passw, jump_host_channel_2)

#delete old files in backup folder
command = "rm -rf /filepath/{*,.*}"
stdin, stdout, stderr = ssh_2.exec_command(command)
lines = stdout.readlines()
#print(lines)

#pause to ensure old directory is cleared
time.sleep(5)

#SCPCLient takes a paramiko transport as an argument, sets up file transfer connection
scp_1 = SCPClient(ssh_1.get_transport())
scp_2 = SCPClient(ssh_2.get_transport())

#get files from 1, store on local machine, put on 2
scp_1.get('/filepath/.', '/target_folder_local/', recursive=True)
scp_2.put('/target_folder_local/.', '/filepath/', recursive=True)

#remove temporary folder
shutil.rmtree(path)

#close connections
ssh_1.close()
ssh_2.close()
jump_host.close()

【问题讨论】:

    标签: python ssh paramiko scp


    【解决方案1】:

    SCPClient 中没有用于跳过隐藏文件或符号链接的 API。


    上传很简单,只要复制SCPClient's code 并根据需要进行修改即可。请参阅_send_recursive 函数中的os.walk 循环。

    如果您不想修改SCPClient 的代码,则必须自己迭代文件,为每个文件调用SCPClient.put。它的效率会稍低一些,因为它会为每个文件启动新的 SCP 服务器。


    对于下载,您可以修改 SCPClient 代码以使用非零代码响应服务器为您不想下载的文件提供的 C 命令。

    检查_recv_file 函数。在name 被解析的地方,检查您不感兴趣的文件的名称或属性,然后执行chan.send('\x01') 并退出该功能。


    虽然你为什么要使用 SCP?使用 SFTP。它更适合您需要的自定义规则。

    Paramiko 没有递归 SFTP 传输功能(但 pysftp 有,请参阅 pysftp vs. Paramiko)。但是你无论如何都不能使用它,同样的原因你不能用它和 SCP 一起使用。满足您的特定需求。

    但是请检查我对Python pysftp get_r from Linux works fine on Linux but not on Windows 的回答。它显示了一个简单的递归 SFTP 下载代码。只需稍作修改即可跳过不想下载的文件。

    类似

    if (not S_ISLNK(mode)) and (not entry.filename.startswith(".")):
    

    (见Checking if a file on SFTP server is a symbolic link, and deleting the symbolic link, using Python Paramiko/pysftp

    【讨论】:

    • 感谢您的回复,我在哪里可以找到SCPClient的相关代码?
    • 我已经为我的答案添加了一个链接。
    • 嗨@MartinPrikryl,很抱歉再次打扰您。我不得不暂停后才回到这个项目。关于您的解决方案 - 这适用于 .put 但是我需要首先防止 .get 获取隐藏文件或符号链接。根据 SCP 代码:get 方法由远程 scp 实例控制,并相应地运行。似乎没有编辑 .get 函数的范围,因为它是在服务器端解决的。对于没有 rsync 的情况下如何实现这一点,我想您不会有任何其他建议?
    • 跳转主机见Port forwarding and the open SFTP using Python Paramiko。尽管您的代码已经这样做了。不是吗?我看到你现在要求 pysftp,而你的代码是用于 Paramiko。你不需要 pysftp。
    • 好的,我明白了,你是说这个,对吧? Python pysftp get_r from Linux works fine on Linux but not on Windows - 虽然它确实是关于 pysftp,但我在此处发布的代码实际上(几乎)也可以直接与 Paramiko 一起使用。我已经在那里编辑了答案。
    猜你喜欢
    • 2012-06-17
    • 2012-09-25
    • 1970-01-01
    • 2011-08-17
    • 2015-07-30
    • 2018-09-02
    • 2022-01-04
    • 1970-01-01
    相关资源
    最近更新 更多