在Rust中如何获取process::Command的完整输出并显示到终端?
问题:Rust中执行scp命令无法显示终端输出及自动填充密码
我正尝试用Rust重构自己的bash脚本(Rust支持哈希与更多自定义功能),但无法将process::Command执行scp命令的输出显示到终端,尝试多种stdout管道方式后仍无进展。我希望在命令行中看到如下scp输出(含密码提示与传输进度)并实现自动填充密码(已知ssh密钥的存在):
user@server's password: ibits.c 100% 1137 271.2KB/s 00:00
我的auto_scp函数代码:
fn auto_scp(flags: FlagOptions, f_path: String) { let info = open_config(); let mut args: Vec<String> = vec![]; if flags.is_folder { args.push(String::from("-r")) } if flags.d_load { let path = info.rmt_hst+":"+&f_path; // println!("{}",path); args.push(path); args.push(info.ddest); } else { let path = info.rmt_hst+":"+&info.udest; // println!("{}",path); args.push(f_path); args.push(path); } let mut com = process::Command::new("/bin/scp") .args(args) .stdout(process::Stdio::piped()) .output() .expect("stuff"); // io::stdout().write_all(b"hello world\n"); // .expect("Could not output"); // let stdout = String::from_utf8(com.stdout).unwrap(); println!("stdout: {}", String::from_utf8(&com.stdout)); // io::stdout().write_all(&outc.stdout).unwrap(); println!("{}", stdout); return; }
解决方案
一、让scp输出直接显示到终端
你的代码用.stdout(process::Stdio::piped())和.output()会把scp的输出捕获到内存,而非直接转发到终端。要实时看到输出,需让子进程继承当前进程的标准输入、输出和错误流,无需手动捕获:
修改命令执行部分:
process::Command::new("/bin/scp") .args(args) .status() .expect("scp command failed");
.status()会等待命令执行完成并返回退出状态,不会捕获输出- 移除
.stdout(process::Stdio::piped()),scp的stdout、stderr会直接关联到当前终端,就能看到密码提示和传输进度
二、自动处理密码(基于SSH密钥)
既然确认SSH密钥存在,优先通过密钥认证跳过密码输入:
- 检查本地私钥权限为
600(执行chmod 600 ~/.ssh/id_rsa) - 确认服务器
~/.ssh/authorized_keys已添加你的公钥,文件权限600、目录权限700 - 如果密钥路径非默认
~/.ssh/id_rsa,在scp参数中添加-i指定路径,比如:args.push("-i".to_string()); args.push("/path/to/your/private/key".to_string());
若必须用密码填充(密钥不可用场景),可借助sshpass工具,修改命令为:
process::Command::new("sshpass") .args(["-p", "your_password", "/bin/scp"]) .args(args) // 原scp参数 .status() .expect("sshpass+scp command failed");
注意:明文写密码有安全风险,优先用SSH密钥认证。
三、完整修改后的函数示例
fn auto_scp(flags: FlagOptions, f_path: String) { let info = open_config(); let mut args: Vec<String> = vec![]; // 如需指定密钥路径,取消下方注释 // args.push("-i".to_string()); // args.push("/path/to/your/private/key".to_string()); if flags.is_folder { args.push(String::from("-r")); } if flags.d_load { let path = format!("{}:{}", info.rmt_hst, f_path); args.push(path); args.push(info.ddest); } else { let path = format!("{}:{}", info.rmt_hst, info.udest); args.push(f_path); args.push(path); } process::Command::new("/bin/scp") .args(args) .status() .expect("Failed to execute scp command"); }
说明:用format!代替字符串拼接更符合Rust习惯,可避免所有权问题。
内容的提问来源于stack exchange,提问作者ConnerWithAnE
相关产品推荐
相关产品推荐

