const fs = require('fs');const path = require('path');const { Client } = require('ssh2');const process = require('process');// 命令行参数解析function parseArgs() { const options = { host: 'ip_address', port: 22, username: 'username', password: 'password', local: '[local_file]', remote: 'target_dir' }; return options;}// 执行远程Linux命令function executeCommand(conn, command) { return new Promise((resolve, reject) => { console.log(`开始执行命令: ${command}`); conn.exec(command, (err, stream) => { if (err) { console.error(`执行命令失败: ${err}`); reject(err); return; } let stdout = ''; let stderr = ''; // 捕获标准输出 stream.on('data', (data) => { stdout += data.toString(); process.stdout.write(data); }); // 捕获标准错误 stream.stderr.on('data', (data) => { stderr += data.toString(); process.stderr.write(data); }); // 处理命令完成 stream.on('close', (code, signal) => { console.log(`命令执行完成,退出码: ${code}`); if (code === 0) { resolve(stdout); } else { reject(new Error(`命令执行失败,退出码: ${code}\n错误信息: ${stderr}`)); } }); // 处理错误 stream.on('error', (err) => { console.error(`命令执行错误: ${err}`); reject(err); }); }); });}// 推送单个文件function pushFile(conn, localFile, remoteDir) { return new Promise((resolve, reject) => { const fileName = path.basename(localFile); const remoteFile = path.posix.join(remoteDir, fileName); console.log(`开始传输: ${localFile} -> ${remoteFile}`); // 获取文件大小 let fileSize = 0; let transferred = 0; try { const stats = fs.statSync(localFile); fileSize = stats.size; console.log(`文件大小: ${(fileSize / 1024 / 1024).toFixed(2)} MB`); } catch (err) { console.error(`获取文件大小失败: ${err}`); reject(err); return; } // 使用ssh2的SFTP功能来传输文件 conn.sftp((err, sftp) => { if (err) { console.error(`SFTP初始化失败: ${err}`); reject(err); return; } // 读取本地文件并写入远程文件 const readStream = fs.createReadStream(localFile); const writeStream = sftp.createWriteStream(remoteFile); // 监听数据传输进度 readStream.on('data', (chunk) => { transferred += chunk.length; const progress = (transferred / fileSize * 100).toFixed(1); console.log(progress); const transferredMB = (transferred / 1024 / 1024).toFixed(2); // 兼容 Windows PowerShell 的进度显示 try { if (process.stdout.clearLine && process.stdout.cursorTo) { // 支持 ANSI 转义序列的终端 process.stdout.clearLine(); process.stdout.cursorTo(0); process.stdout.write(`传输进度: ${progress}% (${transferredMB} MB)`); } else { // 不支持的终端,使用简单的方式 if (progress === '100.0') { console.log(`传输进度: ${progress}% (${transferredMB} MB)`); } } } catch (error) { // 忽略进度显示错误,确保文件传输继续 if (progress === '100.0') { console.log(`传输进度: ${progress}% (${transferredMB} MB)`); } } }); // 处理错误 readStream.on('error', (err) => { console.error(`\n读取本地文件失败: ${err}`); sftp.end(); reject(err); }); writeStream.on('error', (err) => { console.error(`\n写入远程文件失败: ${err}`); sftp.end(); reject(err); }); // 处理完成 writeStream.on('close', () => { console.log(`\n传输成功: ${localFile}`); sftp.end(); resolve(); }); // 开始传输 readStream.pipe(writeStream); }); });}// 主函数async function main() { const options = parseArgs(); // 创建SSH客户端 const conn = new Client(); return new Promise((resolve, reject) => { conn.on('ready', async () => { console.log('SSH连接成功'); try { // 执行命令查看根目录内容 // 逐个传输文件 for (const file of options.local) { await pushFile(conn, file, options.remote); } console.log('文件传输完成,开始解压'); await executeCommand(conn, `cd ${options.remote} && unzip -o ${path.basename(options.local[0])} && ls`); console.log('解压成功'); resolve(); } catch (err) { reject(err); } finally { console.log('SSH连接已关闭'); conn.end(); } }).on('error', (err) => { console.error('SSH连接失败:', err); reject(err); }).connect({ host: options.host, port: options.port, username: options.username, password: options.password }); });}// 运行主函数main().catch((err) => { console.error('执行失败:', err); process.exit(1);});