引入maven库
1 2 3 4 5
| <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>
|
执行单一的命令
过程很简单:
- 发送一串shell命令
- 拿回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| SshInfo ssh = new SshInfo("192.168.x.x", "root", "xxx"); JSch jSch = new JSch(); try { Session session = jSch.getSession(ssh.getUsername(), ssh.getHost()); session.setPassword(ssh.getPassword()); session.setUserInfo(new MyUserInfo()); session.connect();
Channel channel=session.openChannel("exec"); ((ChannelExec)channel).setCommand("cd / && ls");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1024]; while(true){ while(in.available()>0){ int i=in.read(tmp, 0, 1024); if(i<0)break; System.out.print(new String(tmp, 0, i)); } if(channel.isClosed()){ if(in.available()>0) continue; System.out.println("exit-status: "+channel.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } channel.disconnect(); session.disconnect(); } catch (JSchException | IOException e) { e.printStackTrace(); }
|
MyUserInfo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class MyUserInfo implements UserInfo {
@Override public String getPassphrase() { return null; }
@Override public String getPassword() { return null; }
@Override public boolean promptPassword(String s) { return false; }
@Override public boolean promptPassphrase(String s) { return false; }
@Override public boolean promptYesNo(String s) { return s.contains("The authenticity of host"); }
@Override public void showMessage(String s) {
} }
|
上面可以把命令写在一起通过&&
连接然后一起执行,但不够优雅,如果命令很多就不好排错了。
交互式shell
先看一下最后的样子,就和shell一样的:
代码很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void testInteractiveShell() { SshInfo ssh = new SshInfo("192.168.64.12", "root", "123456"); JSch jSch = new JSch(); try { Session session = jSch.getSession(ssh.getUsername(), ssh.getHost()); session.setPassword(ssh.getPassword()); session.setUserInfo(new MyUserInfo()); session.connect();
Channel exec = session.openChannel("shell");
exec.setInputStream(System.in, true); exec.setOutputStream(System.out);
exec.connect(); } catch (JSchException e) { e.printStackTrace(); } }
|
输入输出流重定向
当然,一般情况我们不会用java构造一个shell来玩,我遇到的情况就是希望能在
同一个shell环境下执行一些命令,而不是每条命令都分开执行,比如:
我先执行cd /
, 希望下次执行ls
列出的是根目录的文件,而不是又回到home目录了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| JSch jSch = new JSch(); try { Session session = jSch.getSession(ssh.getUsername(), ssh.getHost()); session.setPassword(ssh.getPassword()); session.setUserInfo(new MyUserInfo()); session.connect();
Channel exec = session.openChannel("shell");
PipedOutputStream pipe = new PipedOutputStream(); PipedInputStream in = new PipedInputStream(pipe); PrintWriter pw = new PrintWriter(pipe);
exec.setInputStream(in, true);
PrintStream out = System.out; ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); System.setOut(ps); exec.setOutputStream(out);
String[] cmds = {"cd /", "ls", "pwd"}; for (String cmd : cmds) { pw.println(cmd); } pw.println("exit"); pw.flush();
exec.connect();
while (!exec.isClosed()) { } System.setOut(out); System.out.println(baos.toString()); exec.disconnect(); session.disconnect(); } catch (JSchException | IOException e) { e.printStackTrace(); }
|
参考
- redirect-console-output-to-string-in-java
- java-api-examples/index.php?api=com.jcraft.jsch.ChannelShell
- Exec.java