我目前需要在ssh进入服务器后对文件运行多个md5操作(> 15000)。但是我当前的实现非常慢,因为为每个md5操作创建了一个使用exec_command的新通道。使用paramiko有更好的方法吗?
def md5(fname):
hash_md5 = hashlib.md5()
if os.path.isfile(fname):
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def connect_server(host1):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host1)
return ssh
for files in install_files:
stdin, stdout, stderr = ssh.exec_command('md5 %s' % files)
file_md5_map[file] = stdout.read().split()[0]
答案 0 :(得分:0)
只调用exec_command
一次的高性能实现(无论您有多少文件!)可能如下所示:
remote_script = '''
exec 2>/dev/null ## writes to stderr will block; suppress them.
bash -s <<'EOF'
while IFS= read -r -d '' filename; do
result=$(md5 "$filename");
result=${result%%[[:space:]]*}
printf '%s\t%s\0' "${result}" "${filename}"
done
EOF
'''
stdin, stdout, stderr = ssh.exec_command(remote_script)
writer_thread = threading.Thread(
target = lambda: stdin.write('\0'.join(install_files) + '\0')
)
writer_thread.start()
for datum in stdout.read().split('\0'):
if len(datum) == 0: continue # should only happen for the last line
(md5sum, filename) = datum.split('\t', 1)
file_md5_map[filename] = md5sum
这会传递远程进程的stdin:
上的文件名流/path/to/file1<NUL>/path/to/file2</NUL>
...并在其标准输出上返回一对配对的md5sums和文件名:
md5_of_file1<TAB>/path/to/file1<NUL>md5_of_file2<TAB>/path/to/file2<NUL>
这意味着您只需要一个远程进程将此输入流转换为输出,并且对具有令人惊讶或恶意名称的文件完全可靠:由于NUL字符不可能存在于文件名中(与换行符不同) ,通常用作分隔符但不应该),使用NUL分隔文件名是完全安全的。