use ssh2::Session;
use std::io::prelude::*;
use std::net::TcpStream;
fn main() {
// Connect to the local SSH server
let tcp = TcpStream::connect("test.rebex.net:22").unwrap();
let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("demo", "password").unwrap();
let commands = ["cd /pub/example/","ls"];
let mut channel = sess.channel_session().unwrap();
let mut s = String::new();
for command in commands {
println!("{}", command);
channel.exec(command).unwrap();
channel.read_to_string(&mut s).unwrap();
println!("{}", s);
}
channel.wait_close();
println!("{}", channel.exit_status().unwrap());
}
For some reason I get the below error:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: Session(-39), msg: "Channel can not be reused" }', src\main.rs:19:31
I have few other questions, but not sure they can fit in the same post:
How can I run multiple commands based on the output of previous commands?
How to make this code work so I can automatically execute a sequence of commands? (Ex: change the password for a given user)
If you want to execute more than one command, you need to rely on the shell of the host.
channel.shell().unwrap();
for command in commands {
channel.write_all(command.as_bytes()).unwrap();
channel.write_all(b"\n").unwrap();
} // Bit inefficient to use separate write calls
channel.send_eof().unwrap();
println!("Waiting for output");
channel.read_to_string(&mut s).unwrap();
println!("{}", s);
However, how to chain several commands in a shell is up to that shell. If, for example, the shell on your target host is a sh/bash/zsh/ash/fish/… and you don't want subsequent commands to be executed if one command fails (and have a reliable exit code), then &&
might be a better choice (but you could also start with set -e
). But if you're doing that, you might as well use exec.
channel.exec(&commands.join(" && ")).unwrap();
channel.read_to_string(&mut s).unwrap();